home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 24 / Amiga Format AFCD24 (Feb 1998, Issue 108).iso / -in_the_mag- / emulation / amiga / uae-0.7.0b2 / src / filesys.c < prev    next >
C/C++ Source or Header  |  1998-01-20  |  80KB  |  2,820 lines

  1.  /*
  2.   * UAE - The Un*x Amiga Emulator
  3.   *
  4.   * Unix file system handler for AmigaDOS
  5.   *
  6.   * Copyright 1996 Ed Hanway
  7.   * Copyright 1996, 1997 Bernd Schmidt
  8.   *
  9.   * Version 0.4: 970308
  10.   *
  11.   * Based on example code (c) 1988 The Software Distillery
  12.   * and published in Transactor for the Amiga, Volume 2, Issues 2-5.
  13.   * (May - August 1989)
  14.   *
  15.   * Known limitations:
  16.   * Does not support ACTION_INHIBIT (big deal).
  17.   * Does not support any 2.0+ packet types (except ACTION_SAME_LOCK)
  18.   * Does not support removable volumes.
  19.   * May not return the correct error code in some cases.
  20.   * Does not check for sane values passed by AmigaDOS.  May crash the emulation
  21.   * if passed garbage values.
  22.   * Could do tighter checks on malloc return values.
  23.   * Will probably fail spectacularly in some cases if the filesystem is
  24.   * modified at the same time by another process while UAE is running.
  25.   */
  26.  
  27. #include "sysconfig.h"
  28. #include "sysdeps.h"
  29.  
  30. #include "config.h"
  31. #include "options.h"
  32. #include "uae.h"
  33. #include "memory.h"
  34. #include "custom.h"
  35. #include "readcpu.h"
  36. #include "newcpu.h"
  37. #include "filesys.h"
  38. #include "autoconf.h"
  39. #include "compiler.h"
  40. #include "zfile.h"
  41. #include "threaddep/penguin.h"
  42.  
  43. /* #define TRACING_ENABLED */
  44. #ifdef TRACING_ENABLED
  45. #define TRACE(x)    do { sprintf x; write_log(warning_buffer); } while(0)
  46. #define DUMPLOCK(u,x)    dumplock(u,x)
  47. #else
  48. #define TRACE(x)
  49. #define DUMPLOCK(u,x)
  50. #endif
  51.  
  52. #define MAKE_CASE_INSENSITIVE
  53.  
  54. /* errors */
  55. #define ERROR_NO_FREE_STORE        103
  56. #define ERROR_OBJECT_IN_USE        202
  57. #define ERROR_OBJECT_EXISTS        203
  58. #define ERROR_DIR_NOT_FOUND        204
  59. #define ERROR_OBJECT_NOT_FOUND        205
  60. #define ERROR_ACTION_NOT_KNOWN        209
  61. #define ERROR_INVALID_LOCK        211
  62. #define ERROR_OBJECT_WRONG_TYPE        212
  63. #define ERROR_DISK_WRITE_PROTECTED    214
  64. #define ERROR_DIRECTORY_NOT_EMPTY    216
  65. #define ERROR_DEVICE_NOT_MOUNTED    218
  66. #define ERROR_SEEK_ERROR        219
  67. #define ERROR_DISK_FULL            221
  68. #define ERROR_DELETE_PROTECTED        222
  69. #define ERROR_WRITE_PROTECTED        223
  70. #define ERROR_READ_PROTECTED        224
  71. #define ERROR_NO_MORE_ENTRIES        232
  72. #define ERROR_NOT_IMPLEMENTED        236
  73.  
  74. #ifndef DONT_HAVE_POSIX
  75. static long dos_errno(void)
  76. {
  77.     int e = errno;
  78.  
  79.     switch(e) {
  80.      case ENOMEM:    return ERROR_NO_FREE_STORE;
  81.      case EEXIST:    return ERROR_OBJECT_EXISTS;
  82.      case EACCES:    return ERROR_WRITE_PROTECTED;
  83.      case ENOENT:    return ERROR_OBJECT_NOT_FOUND;
  84.      case ENOTDIR:    return ERROR_OBJECT_WRONG_TYPE;
  85.      case ENOSPC:    return ERROR_DISK_FULL;
  86.      case EBUSY:           return ERROR_OBJECT_IN_USE;
  87.      case EISDIR:    return ERROR_OBJECT_WRONG_TYPE;
  88. #if defined(ETXTBSY)
  89.      case ETXTBSY:    return ERROR_OBJECT_IN_USE;
  90. #endif
  91. #if defined(EROFS)
  92.      case EROFS:           return ERROR_DISK_WRITE_PROTECTED;
  93. #endif
  94. #if defined(ENOTEMPTY)
  95. #if ENOTEMPTY != EEXIST
  96.      case ENOTEMPTY:    return ERROR_DIRECTORY_NOT_EMPTY;
  97. #endif
  98. #endif
  99.  
  100.      default:
  101.     TRACE((warning_buffer, "Unimplemented error %s\n", strerror(e)));
  102.     return ERROR_NOT_IMPLEMENTED;
  103.     }
  104. }
  105. #endif
  106.  
  107. /*
  108.  * This _should_ be no issue for us, but let's rather use a guaranteed
  109.  * thread safe function if we have one.
  110.  * Well, let's use it once it works.
  111.  */
  112. #if 0 && defined HAVE_READDIR_R
  113.  
  114. static struct dirent *my_readdir (DIR *dirstream, struct dirent *space)
  115. {
  116.     struct dirent *loc;
  117.     if (readdir_r (dirstream, space, &loc) == 0) {
  118.     /* Success */
  119.     return loc;
  120.     }
  121.     return 0;
  122. }
  123.  
  124. #else
  125. #define my_readdir(dirstream, space) readdir(dirstream)
  126. #endif
  127.  
  128. #define FS_STARTUP 0
  129. #define FS_GO_DOWN 1
  130.  
  131. /* AmigaOS "keys" */
  132. struct a_inode {
  133.     struct a_inode *next, *prev;
  134.     struct a_inode *parent;
  135.     struct a_inode *child, *sibling; /* @@@ implement hash tables or something to make this efficient */
  136.     char *aname;
  137.     char *nname;
  138.     int amigaos_mode;
  139.     int shlock;
  140.     uae_u32 uniq;
  141.     unsigned int dir:1;
  142.     unsigned int elock:1;
  143. };
  144.  
  145. typedef struct {
  146.     char *devname; /* device name, e.g. UAE0: */
  147.     uaecptr devname_amiga;
  148.     uaecptr startup;
  149.     char *volname; /* volume name, e.g. CDROM, WORK, etc. */
  150.     char *rootdir; /* root unix directory */
  151.     int readonly; /* disallow write access? */
  152.     int devno;
  153.     
  154.     struct hardfiledata hf;
  155.  
  156.     /* Threading stuff */
  157.     smp_comm_pipe *unit_pipe, *back_pipe;
  158.     penguin_id tid;
  159.     struct _unit *volatile self;
  160. } UnitInfo;
  161.  
  162. #define MAX_UNITS 20
  163. static int num_units = 0, num_filesys_units = 0;
  164. static UnitInfo ui[MAX_UNITS];
  165. uaecptr filesys_initcode;
  166. static uae_u32 fsdevname, hardfileseglist, filesys_configdev;
  167. static uaecptr filesys_parampacket;
  168.  
  169. char * add_filesys_unit(char *volname, char *rootdir, int readonly,
  170.             int secspertrack, int surfaces, int reserved)
  171. {
  172.     UnitInfo *uip;
  173.     if (num_units >= MAX_UNITS) {
  174.     return "Maximum number of file systems mounted";
  175.     }
  176.  
  177.     uip = ui + num_units;
  178.     if (volname != 0) {
  179.     num_filesys_units++;
  180.     uip->volname = my_strdup(volname);
  181.     uip->hf.fd = 0;
  182.     } else {
  183.     FILE *hf;
  184.  
  185.     uip->volname = 0;
  186.     uip->hf.fd = zfile_open (rootdir, "r+b");
  187.     if (uip->hf.fd == 0) {
  188.         readonly = 1;
  189.         uip->hf.fd = zfile_open (rootdir, "rb");
  190.     }
  191.     if (uip->hf.fd == 0) {
  192.         return "Hardfile not found";
  193.     }
  194.     if (secspertrack < 1 || secspertrack > 32767
  195.         || surfaces < 1 || surfaces > 1023
  196.         || reserved < 0 || reserved > 1023) {
  197.         return "Bad hardfile geometry";
  198.     }
  199.     fseek (uip->hf.fd, 0, SEEK_END);
  200.     uip->hf.size = ftell (uip->hf.fd);
  201.     uip->hf.secspertrack = secspertrack;
  202.     uip->hf.surfaces = surfaces;
  203.     uip->hf.reservedblocks = reserved;
  204.     uip->hf.nrcyls = (uip->hf.size >> 9) / (secspertrack * surfaces);
  205.     }
  206.     uip->rootdir = my_strdup (rootdir);
  207.     uip->readonly = readonly;
  208.  
  209.     num_units++;
  210.     return 0;
  211. }
  212.  
  213. int kill_filesys_unit (int nr)
  214. {
  215.     if (nr > num_units || nr < 0)
  216.     return -1;
  217.  
  218.     if (ui[nr].hf.fd != 0)
  219.     fclose (ui[nr].hf.fd);
  220.     num_units--;
  221.     for (; nr < num_units; nr++) {
  222.     ui[nr] = ui[nr+1];
  223.     }
  224.     return 0;
  225. }
  226.  
  227. struct hardfiledata *get_hardfile_data (int nr)
  228. {
  229.     if (nr < 0 || nr >= num_units || ui[nr].volname != 0)
  230.     return 0;
  231.     return &ui[nr].hf;
  232. }
  233.  
  234. int sprintf_filesys_unit(char *buffer, int num)
  235. {
  236.     if (num >= num_units)
  237.     return -1;
  238.     
  239.     if (ui[num].volname != 0)
  240.     sprintf (buffer, "(UAE%d:) Filesystem, %s: %s %s", num, ui[num].volname,
  241.          ui[num].rootdir, ui[num].readonly ? "ro" : "");
  242.     else
  243.     sprintf (buffer, "(UAE%d:) Hardfile, \"%s\", size %d bytes", num,
  244.          ui[num].rootdir, ui[num].hf.size);
  245.     return 0;
  246. }
  247.  
  248. void write_filesys_config(FILE *f)
  249. {
  250.     int i;
  251.     for (i = 0; i < num_units; i++) {
  252.     if (ui[i].volname != 0) {
  253.         fprintf(f, "-%c %s:%s\n", ui[i].readonly ? 'M' : 'm',
  254.             ui[i].volname, ui[i].rootdir);
  255.     } else {
  256.         fprintf(f, "-W %d:%d:%d:%s\n", ui[i].hf.secspertrack,
  257.             ui[i].hf.surfaces, ui[i].hf.reservedblocks,
  258.             ui[i].rootdir);
  259.     }
  260.     }
  261. }
  262.  
  263. /* minimal AmigaDOS definitions */
  264.  
  265. /* field offsets in DosPacket */
  266. #define dp_Type 8
  267. #define dp_Res1    12
  268. #define dp_Res2 16
  269. #define dp_Arg1 20
  270. #define dp_Arg2 24
  271. #define dp_Arg3 28
  272. #define dp_Arg4 32
  273.  
  274. /* result codes */
  275. #define DOS_TRUE ((unsigned long)-1L)
  276. #define DOS_FALSE (0L)
  277.  
  278. /* packet types */
  279. #define ACTION_CURRENT_VOLUME    7
  280. #define ACTION_LOCATE_OBJECT    8
  281. #define ACTION_RENAME_DISK    9
  282. #define ACTION_FREE_LOCK    15
  283. #define ACTION_DELETE_OBJECT    16
  284. #define ACTION_RENAME_OBJECT    17
  285. #define ACTION_COPY_DIR        19
  286. #define ACTION_SET_PROTECT    21
  287. #define ACTION_CREATE_DIR    22
  288. #define ACTION_EXAMINE_OBJECT    23
  289. #define ACTION_EXAMINE_NEXT    24
  290. #define ACTION_DISK_INFO    25
  291. #define ACTION_INFO        26
  292. #define ACTION_FLUSH        27
  293. #define ACTION_SET_COMMENT    28
  294. #define ACTION_PARENT        29
  295. #define ACTION_SET_DATE        34
  296. #define ACTION_FIND_WRITE    1004
  297. #define ACTION_FIND_INPUT    1005
  298. #define ACTION_FIND_OUTPUT    1006
  299. #define ACTION_END        1007
  300. #define ACTION_SEEK        1008
  301. #define ACTION_IS_FILESYSTEM    1027
  302. #define ACTION_READ        'R'
  303. #define ACTION_WRITE        'W'
  304.  
  305. /* 2.0+ packet types */
  306. #define ACTION_INHIBIT       31
  307. #define ACTION_SET_FILE_SIZE 1022
  308. #define ACTION_LOCK_RECORD   2008
  309. #define ACTION_FREE_RECORD   2009
  310. #define ACTION_SAME_LOCK     40
  311. #define ACTION_CHANGE_MODE   1028
  312. #define ACTION_FH_FROM_LOCK  1026
  313. #define ACTION_COPY_DIR_FH   1030
  314. #define ACTION_PARENT_FH     1031
  315. #define ACTION_EXAMINE_FH    1034
  316. #define ACTION_EXAMINE_ALL   1033
  317. #define ACTION_MAKE_LINK     1021
  318. #define ACTION_READ_LINK     1024
  319. #define ACTION_FORMAT        1020
  320. #define ACTION_IS_FILESYSTEM 1027
  321. #define ACTION_ADD_NOTIFY    4097
  322. #define ACTION_REMOVE_NOTIFY 4098
  323.  
  324. #define DISK_TYPE        0x444f5301 /* DOS\1 */
  325.  
  326. typedef struct {
  327.     uae_u32 uniq;
  328.     struct a_inode *aino;
  329.     DIR* dir;
  330. } ExamineKey;
  331.  
  332. typedef struct key {
  333.     struct key *next;
  334.     struct a_inode *aino;
  335.     uae_u32 uniq;
  336.     int fd;
  337.     off_t file_pos;
  338. } Key;
  339.  
  340. /* Since ACTION_EXAMINE_NEXT is so braindamaged, we have to keep
  341.  * some of these around
  342.  */
  343.  
  344. #define EXKEYS 100
  345. #define MAX_AINO_HASH 128
  346.  
  347. /* handler state info */
  348.  
  349. typedef struct _unit {
  350.     struct _unit *next;
  351.  
  352.     /* Amiga stuff */
  353.     uaecptr    dosbase;
  354.     uaecptr    volume;
  355.     uaecptr    port;    /* Our port */
  356.     uaecptr    locklist;
  357.  
  358.     /* Native stuff */
  359.     uae_s32    unit;    /* unit number */
  360.     UnitInfo    ui;    /* unit startup info */
  361.     char    tmpbuf3[256];
  362.  
  363.     /* Dummy message processing */
  364.     uaecptr    dummy_message;
  365.     volatile unsigned int cmds_sent;
  366.     volatile unsigned int cmds_complete;
  367.     volatile unsigned int cmds_acked;
  368.  
  369.     /* ExKeys */
  370.     ExamineKey    examine_keys[EXKEYS];
  371.     int        next_exkey;
  372.  
  373.     /* Keys */
  374.     struct key*    keys;
  375.     uae_u32    key_uniq;
  376.     uae_u32    a_uniq;
  377.  
  378.     struct a_inode rootnode;
  379.     unsigned long aino_cache_size;
  380.     struct a_inode *aino_hash[MAX_AINO_HASH];
  381.     unsigned long nr_cache_hits;
  382.     unsigned long nr_cache_lookups;
  383.  
  384.     /* Reset handling */
  385.     uae_sem_t    reset_sync_sem;
  386.     int        reset_state;
  387. } Unit;
  388.  
  389. typedef uae_u8 *dpacket;
  390. #define PUT_PCK_RES1(p,v) do { do_put_mem_long ((uae_u32 *)((p) + dp_Res1), (v)); } while (0)
  391. #define PUT_PCK_RES2(p,v) do { do_put_mem_long ((uae_u32 *)((p) + dp_Res2), (v)); } while (0)
  392. #define GET_PCK_TYPE(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Type))))
  393. #define GET_PCK_RES1(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Res1))))
  394. #define GET_PCK_RES2(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Res2))))
  395. #define GET_PCK_ARG1(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg1))))
  396. #define GET_PCK_ARG2(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg2))))
  397. #define GET_PCK_ARG3(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg3))))
  398. #define GET_PCK_ARG4(p) ((uae_s32)(do_get_mem_long ((uae_u32 *)((p) + dp_Arg4))))
  399.  
  400. static char *bstr1 (uaecptr addr)
  401. {
  402.     static char buf[256];
  403.     int i;
  404.     int n = get_byte(addr);
  405.     addr++;
  406.  
  407.     for(i = 0; i < n; i++, addr++)
  408.     buf[i] = get_byte(addr);
  409.     buf[i] = 0;
  410.     return buf;
  411. }
  412.  
  413. static char *bstr (Unit *unit, uaecptr addr)
  414. {
  415.     int i;
  416.     int n = get_byte(addr);
  417.  
  418.     addr++;
  419.     for(i = 0; i < n; i++, addr++)
  420.     unit->tmpbuf3[i] = get_byte(addr);
  421.     unit->tmpbuf3[i] = 0;
  422.     return unit->tmpbuf3;
  423. }
  424.  
  425. static char *bstr_cut (Unit *unit, uaecptr addr)
  426. {
  427.     char *p = unit->tmpbuf3;
  428.     int i, colon_seen = 0;
  429.     int n = get_byte (addr);
  430.  
  431.     addr++;
  432.     for(i = 0; i < n; i++, addr++) {
  433.     uae_u8 c = get_byte(addr);
  434.     unit->tmpbuf3[i] = c;
  435.     if (c == '/' || (c == ':' && colon_seen++ == 0))
  436.         p = unit->tmpbuf3 + i + 1;
  437.     }
  438.     unit->tmpbuf3[i] = 0;
  439.     return p;
  440. }
  441.  
  442. static Unit *units = 0;
  443. static int unit_num = 0;
  444.  
  445. static Unit*
  446. find_unit(uaecptr port)
  447. {
  448.     Unit* u;
  449.     for(u = units; u; u = u->next)
  450.     if(u->port == port)
  451.         break;
  452.  
  453.     return u;
  454. }
  455.  
  456. static int get_file_attrs (struct a_inode *aino)
  457. {
  458.     struct stat statbuf;
  459.     if (-1 == stat (aino->nname, &statbuf))
  460.     return dos_errno ();
  461.     aino->dir = S_ISDIR (statbuf.st_mode) ? 1 : 0;
  462.     aino->amigaos_mode =
  463. #ifndef __DOS__
  464.     (S_IXUSR & statbuf.st_mode ? 0 : A_FIBF_EXECUTE) |
  465. #endif
  466.     (S_IWUSR & statbuf.st_mode ? 0 : A_FIBF_WRITE) |
  467. #if 0 /* This makes it impossible to overwrite those. */
  468.     (S_IWUSR & statbuf.st_mode ? 0 : A_FIBF_DELETE) |
  469. #endif
  470.     (S_IRUSR & statbuf.st_mode ? 0 : A_FIBF_READ);
  471.     return 0;
  472. };
  473.  
  474. static int set_file_attrs (struct a_inode *aino, int mask)
  475. {
  476.     struct stat statbuf;
  477.     int mode;
  478.  
  479.     if (-1 == stat(aino->nname, &statbuf))
  480.     return ERROR_OBJECT_NOT_FOUND;
  481.  
  482.     mode = statbuf.st_mode;
  483. #ifdef __unix
  484.     /* Unix dirs behave differently than AmigaOS ones. Just allow anything. */
  485.     if (aino->dir) {
  486.     mask = 0;
  487.     }
  488. #endif
  489.     if (mask & A_FIBF_READ)
  490.     mode &= ~S_IRUSR;
  491.     else
  492.     mode |= S_IRUSR;
  493.  
  494.     if ((mask & A_FIBF_WRITE) != 0 || (mask & A_FIBF_DELETE) != 0)
  495.     mode &= ~S_IWUSR;
  496.     else
  497.     mode |= S_IWUSR;
  498.  
  499.     if (mask & A_FIBF_EXECUTE)
  500.     mode &= ~S_IXUSR;
  501.     else
  502.     mode |= S_IXUSR;
  503.  
  504.     if (-1 == chmod(aino->nname, mode))
  505.     return dos_errno();
  506.  
  507.     aino->amigaos_mode = mask;
  508.  
  509.     return 0;
  510. }
  511.  
  512. static void prepare_for_open (char *name)
  513. {
  514. #if 0
  515.     struct stat statbuf;
  516.     int mode;
  517.  
  518.     if (-1 == stat (name, &statbuf))
  519.     return;
  520.  
  521.     mode = statbuf.st_mode;
  522.     mode |= S_IRUSR;
  523.     mode |= S_IWUSR;
  524.     mode |= S_IXUSR;
  525.     chmod (name, mode);
  526. #endif
  527. }
  528.  
  529. static void de_recycle_aino (Unit *unit, struct a_inode *aino)
  530. {
  531.     if (aino->next == 0 || aino == &unit->rootnode)
  532.     return;
  533.     aino->next->prev = aino->prev;
  534.     aino->prev->next = aino->next;
  535.     aino->next = aino->prev = 0;
  536.     unit->aino_cache_size--;
  537. }
  538.  
  539. static void recycle_aino (Unit *unit, struct a_inode *aino)
  540. {
  541.     if (aino->dir || aino->shlock > 0 || aino->elock || aino == &unit->rootnode)
  542.     /* Still in use */
  543.     return;
  544.  
  545.     /* Chain it into circular list. */
  546.     aino->next = unit->rootnode.next;
  547.     aino->prev = &unit->rootnode;
  548.     aino->prev->next = aino;
  549.     aino->next->prev = aino;
  550.     unit->aino_cache_size++;
  551.     if (unit->aino_cache_size > 500) {
  552.     /* Reap a few. */
  553.     int i = 0;
  554.     while (i < 50) {
  555.         struct a_inode **aip;
  556.         aip = &unit->rootnode.prev->parent->child;
  557.         for (;;) {
  558.         aino = *aip;
  559.         if (aino == 0)
  560.             break;
  561.  
  562.         if (aino->next == 0)
  563.             aip = &aino->sibling;
  564.         else {
  565.             int hash = aino->uniq % MAX_AINO_HASH;
  566.             if (unit->aino_hash[hash] == aino)
  567.             unit->aino_hash[hash] = 0;
  568.  
  569.             aino->next->prev = aino->prev;
  570.             aino->prev->next = aino->next;
  571.             *aip = aino->sibling;
  572.             i++;
  573.  
  574.             if (aino->shlock > 0 || aino->elock)
  575.             write_log ("panic: freeing locked a_inode!\n");
  576.  
  577.             free (aino->nname);
  578.             free (aino->aname);
  579.             free (aino);
  580.         }
  581.         }
  582.     }
  583. #if 0
  584.     {
  585.         char buffer[40];
  586.         sprintf (buffer, "%d ainos reaped.\n", i);
  587.         write_log (buffer);
  588.     }
  589. #endif
  590.     unit->aino_cache_size -= i;
  591.     }
  592. }
  593.  
  594. static void update_child_names (Unit *unit, struct a_inode *a, struct a_inode *parent)
  595. {
  596.     int l0 = strlen (parent->nname) + 2;
  597.  
  598.     while (a != 0) {
  599.     char *name_start;
  600.     char *new_name;
  601.  
  602.     a->parent = parent;
  603.     name_start = strrchr (a->nname, '/');
  604.     if (name_start == 0) {
  605.         write_log ("malformed file name");
  606.     }
  607.     name_start++;
  608.     new_name = (char *)xmalloc (strlen (name_start) + l0);
  609.     strcpy (new_name, parent->nname);
  610.     strcat (new_name, "/");
  611.     strcat (new_name, name_start);
  612.     free (a->nname);
  613.     a->nname = new_name;
  614.     if (a->child)
  615.         update_child_names (unit, a->child, a);
  616.     a = a->sibling;
  617.     }
  618. }
  619.  
  620. static void move_aino_children (Unit *unit, struct a_inode *from, struct a_inode *to)
  621. {
  622.     to->child = from->child;
  623.     from->child = 0;
  624.     update_child_names (unit, to->child, to);
  625. }
  626.  
  627. static void delete_aino (Unit *unit, struct a_inode *aino)
  628. {
  629.     struct a_inode **aip;
  630.     int hash;
  631.  
  632.     TRACE((warning_buffer, "deleting aino %x\n", aino->uniq));
  633.  
  634.     de_recycle_aino (unit, aino);
  635.     aip = &aino->parent->child;
  636.     while (*aip != aino && *aip != 0)
  637.     aip = &(*aip)->sibling;
  638.     if (*aip != aino) {
  639.     write_log ("Couldn't delete aino.\n");
  640.     return;
  641.     }
  642.     hash = aino->uniq % MAX_AINO_HASH;
  643.     if (unit->aino_hash[hash] == aino)
  644.     unit->aino_hash[hash] = 0;
  645.     *aip = aino->sibling;
  646.     free (aino->nname);
  647.     free (aino->aname);
  648.     free (aino);
  649. }
  650.  
  651. static struct a_inode *lookup_sub (struct a_inode *dir, uae_u32 uniq)
  652. {
  653.     struct a_inode **cp = &dir->child;
  654.     struct a_inode *c, *retval;
  655.  
  656.     for (;;) {
  657.     c = *cp;
  658.     if (c == 0)
  659.         return 0;
  660.  
  661.     if (c->uniq == uniq) {
  662.         retval = c;
  663.         break;
  664.     }
  665.     if (c->dir) {
  666.         struct a_inode *a = lookup_sub (c, uniq);
  667.         if (a != 0) {
  668.         retval = a;
  669.         break;
  670.         }
  671.     }
  672.     cp = &c->sibling;
  673.     }
  674.     *cp = c->sibling;
  675.     c->sibling = dir->child;
  676.     dir->child = c;
  677.     return retval;
  678. }
  679.  
  680. static struct a_inode *lookup_aino (Unit *unit, uae_u32 uniq)
  681. {
  682.     struct a_inode *a;
  683.     int hash = uniq % MAX_AINO_HASH;
  684.  
  685.     if (uniq == 0)
  686.     return &unit->rootnode;
  687.     a = unit->aino_hash[hash];
  688.     if (a == 0 || a->uniq != uniq)
  689.     a = lookup_sub (&unit->rootnode, uniq);
  690.     else
  691.     unit->nr_cache_hits++;
  692.     unit->nr_cache_lookups++;
  693.     unit->aino_hash[hash] = a;
  694.     return a;
  695. }
  696.  
  697. /* This gets called to translate an Amiga name that some program used to
  698.  * a name that we can use on the native filesystem. */
  699. static char *get_nname (Unit *unit, struct a_inode *base, char *rel)
  700. {
  701.     DIR* dir;
  702.     struct dirent* de;
  703.     char *p = 0;
  704.  
  705.     dir = opendir(base->nname);
  706.     if (dir) {
  707.     struct dirent de_space;
  708.     while((de = my_readdir (dir, &de_space))) {
  709.         if (strcasecmp(de->d_name, rel) == 0)
  710.         break;
  711.     }
  712.     if (de) {
  713.         p = (char *)xmalloc (strlen (de->d_name) + strlen (base->nname) + 2);
  714.         strcpy (p, base->nname);
  715.         strcat (p, "/");
  716.         strcat (p, de->d_name);
  717.     }
  718.     closedir(dir);
  719.     }
  720.     return p;
  721. }
  722.  
  723. /*
  724.  * This gets called if an ACTION_EXAMINE_NEXT happens and we hit an object
  725.  * for which we know the name on the native filesystem, but no corresponding
  726.  * Amiga filesystem name.
  727.  * @@@ For DOS filesystems, it might make sense to declare the new name
  728.  * "weak", so that it can get overriden by a subsequent call to get_nname().
  729.  * That way, if someone does "dir :" and there is a file "foobar.inf", and
  730.  * someone else tries to open "foobar.info", get_nname() could maybe made to
  731.  * figure out that this is supposed to be the file "foobar.inf".
  732.  * DOS sucks...
  733.  */
  734. static char *get_aname (Unit *unit, struct a_inode *base, char *rel)
  735. {
  736.     char *p = 0;
  737.  
  738.     p = (char *)xmalloc (strlen (rel) + strlen (base->aname) + 2);
  739.     strcpy (p, base->aname);
  740.     strcat (p, "/");
  741.     strcat (p, rel);
  742.  
  743.     return p;
  744. }
  745.  
  746. static struct a_inode *new_child_aino (Unit *unit, struct a_inode *base, char *rel, int force)
  747. {
  748.     struct stat statbuf;
  749.     char *nn;
  750.     struct a_inode *aino;
  751.  
  752.     nn = get_nname (unit, base, rel);
  753.     if (nn == 0 && !force)
  754.     return 0;
  755.     else if (nn != 0)
  756.     force = 0;
  757.  
  758.     aino = (struct a_inode *)malloc (sizeof (struct a_inode));
  759.     if (aino == 0)
  760.     return 0;
  761.     aino->aname = my_strdup (rel);
  762.     if (nn == 0) {
  763.     nn = (char *)xmalloc (strlen (base->nname) + strlen (rel) + 2);
  764.     strcpy (nn, base->nname);
  765.     strcat (nn, "/");
  766.     strcat (nn, rel);
  767.     free (rel);
  768.     }
  769.     aino->nname = nn;
  770.     aino->uniq = ++unit->a_uniq;
  771.     if (unit->a_uniq == 0xFFFFFFFF) {
  772.     write_log ("Running out of a_inodes (prepare for big trouble)!\n");
  773.     }
  774.     aino->shlock = 0;
  775.     aino->elock = 0;
  776.  
  777.     /* Update tree structure */
  778.     aino->parent = base;
  779.     aino->child = 0;
  780.     aino->sibling = base->child;
  781.     base->child = aino;
  782.     aino->next = aino->prev = 0;
  783.  
  784.     if (force == 2) {
  785.     aino->dir = 1;
  786.     aino->amigaos_mode = 0;
  787.     } else if (force == 1) {
  788.     aino->dir = 0;
  789.     aino->amigaos_mode = 0;
  790.     } else {
  791.     get_file_attrs (aino);
  792.     }
  793.     recycle_aino (unit, aino);
  794.     TRACE((warning_buffer, "created aino %x, normal\n", aino->uniq));
  795.     return aino;
  796. }
  797.  
  798. static struct a_inode *lookup_child_aino (Unit *unit, struct a_inode *base, char *rel, uae_u32 *err)
  799. {
  800.     struct a_inode *c = base->child;
  801.     char *p, *p2;
  802.     int l0 = strlen (rel);
  803.  
  804.     if (base->dir == 0) {
  805.     *err = ERROR_OBJECT_WRONG_TYPE;
  806.     return 0;
  807.     }
  808.  
  809.     while (c != 0) {
  810.     int l1 = strlen (c->aname);
  811.     if (l0 <= l1 && strcasecmp (rel, c->aname + l1 - l0) == 0
  812.         && (l0 == l1 || c->aname[l1-l0-1] == '/'))
  813.         break;
  814.     c = c->sibling;
  815.     }
  816.     if (c != 0)
  817.     return c;
  818.     c = new_child_aino (unit, base, rel, 0);
  819.     if (c == 0)
  820.     *err = ERROR_OBJECT_NOT_FOUND;
  821.     return c;
  822. }
  823.  
  824. /* Different version because this one compares with the nname */
  825. static struct a_inode *lookup_child_aino_for_exnext (Unit *unit, struct a_inode *base, char *rel, uae_u32 *err)
  826. {
  827.     struct a_inode *c = base->child;
  828.     char *p, *p2;
  829.     int l0 = strlen (rel);
  830.  
  831.     *err = 0;
  832.     while (c != 0) {
  833.     int l1 = strlen (c->nname);
  834.     if (l0 <= l1 && strcasecmp (rel, c->nname + l1 - l0) == 0
  835.         && (l0 == l1 || c->nname[l1-l0-1] == '/'))
  836.         break;
  837.     c = c->sibling;
  838.     }
  839.     if (c != 0)
  840.     return c;
  841.     c = (struct a_inode *)malloc (sizeof (struct a_inode));
  842.     if (c == 0)
  843.     *err = ERROR_NO_FREE_STORE;
  844.     else {
  845.     c->nname = (char *)xmalloc (strlen (base->nname) + l0 + 2);
  846.     strcpy (c->nname, base->nname);
  847.     strcat (c->nname, "/");
  848.     strcat (c->nname, rel);
  849.     c->aname = get_aname (unit, base, rel);
  850.     c->uniq = ++unit->a_uniq;
  851.     if (unit->a_uniq == 0xFFFFFFFF) {
  852.         write_log ("Running out of a_inodes (prepare for big trouble)!\n");
  853.     }
  854.     c->shlock = 0;
  855.     c->elock = 0;
  856.  
  857.     /* Update tree structure */
  858.     c->parent = base;
  859.     c->child = 0;
  860.     c->sibling = base->child;
  861.     base->child = c;
  862.     c->next = c->prev = 0;
  863.  
  864.     get_file_attrs (c);
  865.     recycle_aino (unit, c);
  866.     TRACE((warning_buffer, "created aino %x, exnext\n", c->uniq));
  867.     }
  868.     return c;
  869. }
  870.  
  871. static struct a_inode *get_aino(Unit* unit, struct a_inode *base, const char *rel, uae_u32 *err)
  872. {
  873.     char *tmp;
  874.     char *p;
  875.     char *r;
  876.     struct a_inode *curr;
  877.     int i;
  878.  
  879.     *err = 0;
  880.     TRACE((warning_buffer, "get_path(%s,%s)\n", base->aname, rel));
  881.  
  882.     /* root-relative path? */
  883.     for(i = 0; rel[i] && rel[i] != '/' && rel[i] != ':'; i++)
  884.     ;
  885.     if (':' == rel[i])
  886.     rel += i+1;
  887.  
  888.     tmp = my_strdup (rel);
  889.     p = tmp;
  890.     curr = base;
  891.  
  892.     while(*p) {
  893.     /* start with a slash? go up a level. */
  894.     if (*p == '/') {
  895.         if (curr->parent != 0)
  896.         curr = curr->parent;
  897.         p++;
  898.     } else {
  899.         struct a_inode *next;
  900.  
  901.         char *component_end;
  902.         component_end = strchr (p, '/');
  903.         if (component_end != 0)
  904.         *component_end = '\0';
  905.         next = lookup_child_aino (unit, curr, p, err);
  906.         if (next == 0) {
  907.         /* if only last component not found, return parent dir. */
  908.         if (*err != ERROR_OBJECT_NOT_FOUND || component_end != 0)
  909.             curr = 0;
  910.         /* ? what error is appropriate? */
  911.         break;
  912.         }
  913.         curr = next;
  914.         if (component_end)
  915.         p = component_end+1;
  916.         else
  917.         break;
  918.  
  919.     }
  920.     }
  921.     free (tmp);
  922.     return curr;
  923. }
  924.  
  925. static uae_u32 startup_handler (void)
  926. {
  927.     /* Just got the startup packet. It's in A4. DosBase is in A2,
  928.      * our allocated volume structure is in D6, A5 is a pointer to
  929.      * our port. */
  930.     uaecptr rootnode = get_long(m68k_areg (regs, 2) + 34);
  931.     uaecptr dos_info = get_long(rootnode + 24) << 2;
  932.     uaecptr pkt = m68k_dreg (regs, 3);
  933.     uaecptr arg2 = get_long (pkt + dp_Arg2);
  934.     int i, namelen;
  935.     char* devname = bstr1 (get_long (pkt + dp_Arg1) << 2);
  936.     char* s;
  937.     Unit* unit;
  938.     UnitInfo *uinfo;
  939.  
  940.     /* find UnitInfo with correct device name */
  941.     s = strchr(devname, ':');
  942.     if(s)
  943.     *s = '\0';
  944.  
  945.     for(i = 0; i < num_units; i++) {
  946.     /* Hardfile volume name? */
  947.     if (ui[i].volname == 0)
  948.         continue;
  949.  
  950.     if (ui[i].startup == arg2)
  951.         break;
  952.     }
  953.  
  954.     if(i == num_units || 0 != access(ui[i].rootdir, R_OK)) {
  955.     sprintf(warning_buffer, "Failed attempt to mount device\n", devname);
  956.     write_log (warning_buffer);
  957.     put_long (pkt + dp_Res1, DOS_FALSE);
  958.     put_long (pkt + dp_Res2, ERROR_DEVICE_NOT_MOUNTED);
  959.     return 1;
  960.     }
  961.     uinfo = ui + i;
  962.  
  963.     unit = (Unit *) xmalloc (sizeof (Unit));
  964.     unit->next = units;
  965.     units = unit;
  966.     uinfo->self = unit;
  967.  
  968.     unit->volume = 0;
  969.     unit->reset_state = FS_STARTUP;
  970.     unit->port = m68k_areg(regs, 5);
  971.     unit->unit = unit_num++;
  972.  
  973.     unit->ui.devname = uinfo->devname;
  974.     unit->ui.volname = my_strdup (uinfo->volname); /* might free later for rename */
  975.     unit->ui.rootdir = uinfo->rootdir;
  976.     unit->ui.readonly = uinfo->readonly;
  977.     unit->ui.unit_pipe = uinfo->unit_pipe;
  978.     unit->ui.back_pipe = uinfo->back_pipe;
  979.     unit->cmds_complete = 0;
  980.     unit->cmds_sent = 0;
  981.     unit->cmds_acked = 0;
  982.     for (i = 0; i < EXKEYS; i++) {
  983.     unit->examine_keys[i].aino = 0;
  984.     unit->examine_keys[i].dir = 0;
  985.     unit->examine_keys[i].uniq = 0;
  986.     }
  987.     unit->next_exkey = 1;
  988.     unit->keys = 0;
  989.     unit->a_uniq = unit->key_uniq = 0;
  990.  
  991.     unit->rootnode.aname = uinfo->volname;
  992.     unit->rootnode.nname = uinfo->rootdir;
  993.     unit->rootnode.sibling = 0;
  994.     unit->rootnode.next = unit->rootnode.prev = &unit->rootnode;
  995.     unit->rootnode.uniq = 0;
  996.     unit->rootnode.parent = 0;
  997.     unit->rootnode.child = 0;
  998.     unit->rootnode.dir = 1;
  999.     unit->rootnode.amigaos_mode = 0;
  1000.     unit->rootnode.shlock = 0;
  1001.     unit->rootnode.elock = 0;
  1002.     unit->aino_cache_size = 0;
  1003.     for (i = 0; i < MAX_AINO_HASH; i++)
  1004.     unit->aino_hash[i] = 0;
  1005.  
  1006. /*    write_comm_pipe_int (unit->ui.unit_pipe, -1, 1);*/
  1007.  
  1008.     TRACE((warning_buffer, "**** STARTUP volume %s\n", unit->ui.volname));
  1009.  
  1010.     /* fill in our process in the device node */
  1011.     put_long ((get_long (pkt + dp_Arg3) << 2) + 8, unit->port);
  1012.     unit->dosbase = m68k_areg(regs, 2);
  1013.  
  1014.     /* make new volume */
  1015.     unit->volume = m68k_areg (regs, 3) + 32;
  1016. #ifdef UAE_FILESYS_THREADS
  1017.     unit->locklist = m68k_areg (regs, 3) + 8;
  1018. #else
  1019.     unit->locklist = m68k_areg (regs, 3);
  1020. #endif
  1021.     unit->dummy_message = m68k_areg (regs, 3) + 12;
  1022.  
  1023.     put_long (unit->dummy_message + 10, 0);
  1024.  
  1025.     put_long (unit->volume + 4, 2); /* Type = dt_volume */
  1026.     put_long (unit->volume + 12, 0); /* Lock */
  1027.     put_long (unit->volume + 16, 3800); /* Creation Date */
  1028.     put_long (unit->volume + 20, 0);
  1029.     put_long (unit->volume + 24, 0);
  1030.     put_long (unit->volume + 28, 0); /* lock list */
  1031.     put_long (unit->volume + 40, (unit->volume + 44) >> 2); /* Name */
  1032.     namelen = strlen (unit->ui.volname);
  1033.     put_byte (unit->volume + 44, namelen);
  1034.     for(i = 0; i < namelen; i++)
  1035.     put_byte (unit->volume + 45 + i, unit->ui.volname[i]);
  1036.  
  1037.     /* link into DOS list */
  1038.     put_long (unit->volume, get_long(dos_info + 4));
  1039.     put_long (dos_info + 4, unit->volume >> 2);
  1040.  
  1041.     put_long (unit->volume + 8, unit->port);
  1042.     put_long (unit->volume + 32, DISK_TYPE);
  1043.  
  1044.     put_long (pkt + dp_Res1, DOS_TRUE);
  1045.     return 0;
  1046. }
  1047.  
  1048. #ifdef HAVE_STATFS
  1049. static void
  1050. do_info(Unit* unit, dpacket packet, uaecptr info)
  1051. {
  1052.     struct statfs statbuf;
  1053. #if STATFS_NO_ARGS == 2
  1054.     if(-1 == statfs(unit->ui.rootdir, &statbuf))
  1055. #else
  1056.     if(-1 == statfs(unit->ui.rootdir, &statbuf, sizeof(struct statfs), 0))
  1057. #endif
  1058.     {
  1059.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1060.     PUT_PCK_RES2 (packet, dos_errno ());
  1061.     }
  1062.  
  1063.     put_long(info, 0); /* errors */
  1064.     put_long(info + 4, unit->unit); /* unit number */
  1065.     put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state  */
  1066.     put_long(info + 12, statbuf.f_blocks); /* numblocks */
  1067.     put_long(info + 16, statbuf.f_blocks - statbuf.STATBUF_BAVAIL); /* inuse */
  1068.     put_long(info + 20, statbuf.f_bsize); /* bytesperblock */
  1069.     put_long(info + 24, DISK_TYPE); /* disk type */
  1070.     put_long(info + 28, unit->volume >> 2); /* volume node */
  1071.     put_long(info + 32, 0); /* inuse */
  1072.     PUT_PCK_RES1 (packet, DOS_TRUE);
  1073. }
  1074. #else
  1075. static void
  1076. do_info(Unit* unit, dpacket packet, uaecptr info)
  1077. {
  1078.     put_long(info, 0); /* errors */
  1079.     put_long(info + 4, unit->unit); /* unit number */
  1080.     put_long(info + 8, unit->ui.readonly ? 80 : 82); /* state  */
  1081.     put_long(info + 12, 256); /* numblocks */
  1082.     put_long(info + 16, 128); /* inuse */
  1083.     put_long(info + 20, 512); /* bytesperblock */
  1084.     put_long(info + 24, DISK_TYPE); /* disk type */
  1085.     put_long(info + 28, unit->volume >> 2); /* volume node */
  1086.     put_long(info + 32, 0); /* inuse */
  1087.     PUT_PCK_RES1 (packet, DOS_TRUE);
  1088. }
  1089. #endif
  1090.  
  1091. static void
  1092. action_disk_info(Unit* unit, dpacket packet)
  1093. {
  1094.     TRACE((warning_buffer, "ACTION_DISK_INFO\n"));
  1095.     do_info(unit, packet, GET_PCK_ARG1 (packet) << 2);
  1096. }
  1097.  
  1098. static void
  1099. action_info(Unit* unit, dpacket packet)
  1100. {
  1101.     TRACE((warning_buffer, "ACTION_INFO\n"));
  1102.     do_info(unit, packet, GET_PCK_ARG2 (packet) << 2);
  1103. }
  1104.  
  1105. static void free_key (Unit *unit, Key*k)
  1106. {
  1107.     Key *k1;
  1108.     Key *prev = 0;
  1109.     for (k1 = unit->keys; k1; k1 = k1->next) {
  1110.     if (k == k1) {
  1111.         if(prev)
  1112.         prev->next = k->next;
  1113.         else
  1114.         unit->keys = k->next;
  1115.         break;
  1116.     }
  1117.     prev = k1;
  1118.     }
  1119.  
  1120.     if (k->fd >= 0)
  1121.     close(k->fd);
  1122.  
  1123.     free(k);
  1124. }
  1125.  
  1126. static Key *lookup_key(Unit *unit, uae_u32 uniq)
  1127. {
  1128.     Key *k;
  1129.     /* It's hardly worthwhile to optimize this - most of the time there are
  1130.      * only one or zero keys. */
  1131.     for(k = unit->keys; k; k = k->next) {
  1132.     if (uniq == k->uniq)
  1133.         return k;
  1134.     }
  1135.     write_log ("Error: couldn't find key!\n");
  1136. #if 0
  1137.     exit(1);
  1138.     /* NOTREACHED */
  1139. #endif
  1140.     /* There isn't much hope we will recover. Unix would kill the process,
  1141.      * AmigaOS gets killed by it. */
  1142.     write_log ("Better reset that Amiga - the system is messed up.\n");
  1143.     return 0;
  1144. }
  1145.  
  1146. static Key *new_key(Unit *unit)
  1147. {
  1148.     Key *k = (Key*) xmalloc(sizeof(Key));
  1149.     k->uniq = ++unit->key_uniq;
  1150.     k->fd = -1;
  1151.     k->file_pos = 0;
  1152.     k->next = unit->keys;
  1153.     unit->keys = k;
  1154.  
  1155.     return k;
  1156. }
  1157.  
  1158. static void
  1159. dumplock(Unit *unit, uaecptr lock)
  1160. {
  1161.     struct a_inode *a;
  1162.     TRACE((warning_buffer, "LOCK: 0x%lx", lock));
  1163.     if(!lock) {
  1164.     TRACE((warning_buffer, "\n"));
  1165.     return;
  1166.     }
  1167.     TRACE((warning_buffer, "{ next=0x%lx, mode=%ld, handler=0x%lx, volume=0x%lx, aino %lx ",
  1168.        get_long(lock) << 2, get_long(lock+8),
  1169.        get_long(lock+12), get_long(lock+16),
  1170.        get_long(lock + 4)));
  1171.     a = lookup_aino (unit, get_long (lock + 4));
  1172.     if (a == 0) {
  1173.     TRACE((warning_buffer, "not found!"));
  1174.     } else {
  1175.     TRACE((warning_buffer, "%s", a->nname));
  1176.     }
  1177.     TRACE((warning_buffer, " }\n"));
  1178. }
  1179.  
  1180. static struct a_inode *find_aino(Unit* unit, uaecptr lock, const char *name, uae_u32 *err)
  1181. {
  1182.     struct a_inode *a;
  1183.  
  1184.     if (lock) {
  1185.     struct a_inode *olda = lookup_aino (unit, get_long(lock + 4));
  1186.     if (olda == 0) {
  1187.         /* That's the best we can hope to do. */
  1188.         a = get_aino (unit, &unit->rootnode, name, err);
  1189.     } else {
  1190.         TRACE((warning_buffer, "aino: 0x%08lx", (unsigned long int)olda->uniq));
  1191.         TRACE((warning_buffer, " \"%s\"\n", olda->nname));
  1192.         a = get_aino (unit, olda, name, err);
  1193.     }
  1194.     } else {
  1195.     a = get_aino (unit, &unit->rootnode, name, err);
  1196.     }
  1197.     if (a) {
  1198.     TRACE((warning_buffer, "aino=\"%s\"\n", a->nname));
  1199.     }
  1200.     return a;
  1201. }
  1202.  
  1203. static uaecptr make_lock (Unit* unit, uae_u32 uniq, long mode)
  1204. {
  1205.     /* allocate lock from the list kept by the assembly code */
  1206.     uaecptr lock;
  1207.  
  1208.     lock = get_long (unit->locklist);
  1209.     put_long (unit->locklist, get_long (lock));
  1210.     lock += 4;
  1211.  
  1212.     put_long(lock + 4, uniq);
  1213.     put_long(lock + 8, mode);
  1214.     put_long(lock + 12, unit->port);
  1215.     put_long(lock + 16, unit->volume >> 2);
  1216.  
  1217.     /* prepend to lock chain */
  1218.     put_long(lock, get_long(unit->volume + 28));
  1219.     put_long(unit->volume + 28, lock >> 2);
  1220.  
  1221.     DUMPLOCK(unit, lock);
  1222.     return lock;
  1223. }
  1224.  
  1225. static void free_lock (Unit* unit, uaecptr lock)
  1226. {
  1227.     Key *k;
  1228.     if(!lock)
  1229.     return;
  1230.  
  1231.     if (lock == get_long(unit->volume + 28) << 2) {
  1232.     put_long(unit->volume + 28, get_long(lock));
  1233.     } else {
  1234.     uaecptr current = get_long(unit->volume + 28);
  1235.     uaecptr next = 0;
  1236.     while(current) {
  1237.         next = get_long(current << 2);
  1238.         if(lock == next << 2)
  1239.         break;
  1240.         current = next;
  1241.     }
  1242.     put_long(current << 2, get_long(lock));
  1243.     }
  1244.     lock -= 4;
  1245.     put_long (lock, get_long (unit->locklist));
  1246.     put_long (unit->locklist, lock);
  1247. }
  1248.  
  1249. static void
  1250. action_lock(Unit* unit, dpacket packet)
  1251. {
  1252.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  1253.     uaecptr name = GET_PCK_ARG2 (packet) << 2;
  1254.     long mode = GET_PCK_ARG3 (packet);
  1255.     struct a_inode *a;
  1256.     uae_u32 err;
  1257.  
  1258.     if (mode != -2 && mode != -1) {
  1259.     TRACE((warning_buffer, "Bad mode.\n"));
  1260.     mode = -2;
  1261.     }
  1262.  
  1263.     TRACE((warning_buffer, "ACTION_LOCK(0x%lx, \"%s\", %d)\n", lock, bstr (unit, name), mode));
  1264.     DUMPLOCK(unit, lock);
  1265.  
  1266.     a = find_aino (unit, lock, bstr (unit, name), &err);
  1267.     if (err == 0 && (a->elock || (mode != -2 && a->shlock > 0))) {
  1268.     err = ERROR_OBJECT_IN_USE;
  1269.     }
  1270.     /* Lock() doesn't do access checks. */
  1271.     if (err != 0) {
  1272.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1273.     PUT_PCK_RES2 (packet, err);
  1274.     return;
  1275.     }
  1276.     if (mode == -2)
  1277.     a->shlock++;
  1278.     else
  1279.     a->elock = 1;
  1280.     de_recycle_aino (unit, a);
  1281.     PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, mode) >> 2);
  1282. }
  1283.  
  1284. static void action_free_lock (Unit* unit, dpacket packet)
  1285. {
  1286.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  1287.     struct a_inode *a;
  1288.     TRACE((warning_buffer, "ACTION_FREE_LOCK(0x%lx)\n", lock));
  1289.     DUMPLOCK(unit, lock);
  1290.  
  1291.     a = lookup_aino (unit, get_long (lock + 4));
  1292.     if (a == 0) {
  1293.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1294.     PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND);
  1295.     return;
  1296.     }
  1297.     if (a->elock)
  1298.     a->elock = 0;
  1299.     else
  1300.     a->shlock--;
  1301.     recycle_aino (unit, a);
  1302.     free_lock(unit, lock);
  1303.  
  1304.     PUT_PCK_RES1 (packet, DOS_TRUE);
  1305. }
  1306.  
  1307. static void
  1308. action_dup_lock(Unit* unit, dpacket packet)
  1309. {
  1310.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  1311.     struct a_inode *a;
  1312.     TRACE((warning_buffer, "ACTION_DUP_LOCK(0x%lx)\n", lock));
  1313.     DUMPLOCK(unit, lock);
  1314.  
  1315.     if(!lock) {
  1316.     PUT_PCK_RES1 (packet, 0);
  1317.     return;
  1318.     }
  1319.     a = lookup_aino (unit, get_long (lock + 4));
  1320.     if (a == 0) {
  1321.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1322.     PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND);
  1323.     return;
  1324.     }
  1325.     /* DupLock()ing exclusive locks isn't possible, says the Autodoc, but
  1326.      * at least the RAM-Handler seems to allow it. Let's see what happens
  1327.      * if we don't. */
  1328.     if (a->elock) {
  1329.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1330.     PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
  1331.     return;
  1332.     }
  1333.     a->shlock++;
  1334.     de_recycle_aino (unit, a);
  1335.     PUT_PCK_RES1 (packet, make_lock (unit, a->uniq, -2) >> 2);
  1336. }
  1337.  
  1338. /* convert time_t to/from AmigaDOS time */
  1339. const int secs_per_day = 24 * 60 * 60;
  1340. const int diff = (8 * 365 + 2) * (24 * 60 * 60);
  1341.  
  1342. static void
  1343. get_time(time_t t, long* days, long* mins, long* ticks)
  1344. {
  1345.     /* time_t is secs since 1-1-1970 */
  1346.     /* days since 1-1-1978 */
  1347.     /* mins since midnight */
  1348.     /* ticks past minute @ 50Hz */
  1349.  
  1350.     t -= diff;
  1351.     *days = t / secs_per_day;
  1352.     t -= *days * secs_per_day;
  1353.     *mins = t / 60;
  1354.     t -= *mins * 60;
  1355.     *ticks = t * 50;
  1356. }
  1357.  
  1358. static time_t
  1359. put_time(long days, long mins, long ticks)
  1360. {
  1361.     time_t t;
  1362.     t = ticks / 50;
  1363.     t += mins * 60;
  1364.     t += days * secs_per_day;
  1365.     t += diff;
  1366.  
  1367.     return t;
  1368. }
  1369.  
  1370. static void free_exkey(ExamineKey* ek)
  1371. {
  1372.     ek->aino = 0;
  1373.     ek->uniq = 0;
  1374.     if (ek->dir)
  1375.     closedir (ek->dir);
  1376. }
  1377.  
  1378. /* This is so sick... who invented ACTION_EXAMINE_NEXT? What did he THINK??? */
  1379. static ExamineKey *new_exkey(Unit *unit, struct a_inode *aino)
  1380. {
  1381.     uae_u32 uniq;
  1382.     uae_u32 oldest = 0xFFFFFFFF;
  1383.     ExamineKey *ek, *oldest_ek = 0;
  1384.     int i;
  1385.  
  1386.     ek = unit->examine_keys;
  1387.     for (i = 0; i < EXKEYS; i++, ek++) {
  1388.     /* Did we find a free one? */
  1389.     if (ek->aino == 0)
  1390.         continue;
  1391.     if (ek->uniq < oldest)
  1392.         oldest = (oldest_ek = ek)->uniq;
  1393.     }
  1394.     ek = unit->examine_keys;
  1395.     for (i = 0; i < EXKEYS; i++, ek++) {
  1396.     /* Did we find a free one? */
  1397.     if (ek->aino == 0)
  1398.         goto found;
  1399.     }
  1400.     /* This message should usually be harmless. */
  1401.     write_log ("Houston, we have a problem.\n");
  1402.     free_exkey (oldest_ek);
  1403.     ek = oldest_ek;
  1404.     found:
  1405.  
  1406.     uniq = unit->next_exkey;
  1407.     if (uniq == 0xFFFFFFFF) {
  1408.     /* Things will probably go wrong, but most likely the Amiga will crash
  1409.      * before this happens because of something else. */
  1410.     uniq = 1;
  1411.     }
  1412.     unit->next_exkey = uniq+1;
  1413.     ek->aino = aino;
  1414.     ek->dir = 0;
  1415.     ek->uniq = uniq;
  1416.     return ek;
  1417. }
  1418.  
  1419. static ExamineKey *lookup_exkey(Unit *unit, uae_u32 uniq)
  1420. {
  1421.     ExamineKey *ek;
  1422.     int i;
  1423.  
  1424.     ek = unit->examine_keys;
  1425.     for (i = 0; i < EXKEYS; i++, ek++) {
  1426.     /* Did we find a free one? */
  1427.     if (ek->uniq == uniq)
  1428.         return ek;
  1429.     }
  1430.     write_log ("Houston, we have a BIG problem.\n");
  1431.     return 0;
  1432. }
  1433.  
  1434. static void
  1435. get_fileinfo(Unit *unit, dpacket packet, uaecptr info, struct a_inode *aino)
  1436. {
  1437.     struct stat statbuf;
  1438.     long days, mins, ticks;
  1439.     int i, n;
  1440.     char *x;
  1441.     uae_u32 err;
  1442.  
  1443.     /* No error checks - this had better work. */
  1444.     stat (aino->nname, &statbuf);
  1445.  
  1446.     if (aino->parent == 0) {
  1447.     x = unit->ui.volname;
  1448.     put_long (info + 4, 1);
  1449.     put_long (info + 120, 1);
  1450.     } else {
  1451.     /* AmigaOS docs say these have to contain the same value. */
  1452.     put_long(info + 4, aino->dir ? 2 : -3);
  1453.     put_long(info + 120, aino->dir ? 2 : -3);
  1454.     x = strrchr (aino->aname, '/');
  1455.     if (x)
  1456.         x++;
  1457.     else
  1458.         x = aino->aname;
  1459.     }
  1460.     TRACE((warning_buffer, "name=\"%s\"\n", x));
  1461.     n = strlen(x);
  1462.     if (n > 106)
  1463.     n = 106;
  1464.     i = 8;
  1465.     put_byte(info + i, n); i++;
  1466.     while(n--)
  1467.     put_byte(info + i, *x), i++, x++;
  1468.     while(i < 108)
  1469.     put_byte(info + i, 0), i++;
  1470.  
  1471.     put_long (info + 116, aino->amigaos_mode);
  1472.     put_long(info + 124, statbuf.st_size);
  1473. #ifdef HAVE_ST_BLOCKS
  1474.     put_long(info + 128, statbuf.st_blocks);
  1475. #else
  1476.     put_long(info + 128, statbuf.st_size / 512 + 1);
  1477. #endif
  1478.     get_time(statbuf.st_mtime, &days, &mins, &ticks);
  1479.     put_long(info + 132, days);
  1480.     put_long(info + 136, mins);
  1481.     put_long(info + 140, ticks);
  1482.     put_long(info + 144, 0); /* no comment */
  1483.     PUT_PCK_RES1 (packet, DOS_TRUE);
  1484. }
  1485.  
  1486. static void do_examine(Unit *unit, dpacket packet, ExamineKey* ek, uaecptr info)
  1487. {
  1488.     struct dirent de_space;
  1489.     struct dirent* de;
  1490.     struct a_inode *aino;
  1491.     uae_u32 err;
  1492.  
  1493.     if (!ek->dir) {
  1494.     ek->dir = opendir (ek->aino->nname);
  1495.     }
  1496.     if (!ek->dir) {
  1497.     free_exkey (ek);
  1498.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1499.     PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
  1500.     return;
  1501.     }
  1502.  
  1503.     de = my_readdir (ek->dir, &de_space);
  1504.  
  1505.     while (de && (0 == strcmp(".", de->d_name)
  1506.          || 0 == strcmp("..", de->d_name)))
  1507.     {
  1508.     de = my_readdir (ek->dir, &de_space);
  1509.     }
  1510.  
  1511.     if (!de) {
  1512.     TRACE((warning_buffer, "no more entries\n"));
  1513.     free_exkey (ek);
  1514.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1515.     PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
  1516.     return;
  1517.     }
  1518.  
  1519.     TRACE((warning_buffer, "entry=\"%s\"\n", de->d_name));
  1520.     aino = lookup_child_aino_for_exnext (unit, ek->aino, de->d_name, &err);
  1521.     if (err != 0) {
  1522.     write_log ("Severe problem in ExNext.\n");
  1523.     free_exkey (ek);
  1524.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1525.     PUT_PCK_RES2 (packet, err);
  1526.     return;
  1527.     }
  1528.     get_fileinfo (unit, packet, info, aino);
  1529. }
  1530.  
  1531. static void action_examine_object (Unit* unit, dpacket packet)
  1532. {
  1533.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  1534.     uaecptr info = GET_PCK_ARG2 (packet) << 2;
  1535.     ExamineKey* ek;
  1536.     struct a_inode *aino = 0;
  1537.  
  1538.     TRACE((warning_buffer, "ACTION_EXAMINE_OBJECT(0x%lx,0x%lx)\n", lock, info));
  1539.     DUMPLOCK(unit, lock);
  1540.  
  1541.     if (lock != 0)
  1542.     aino = lookup_aino (unit, get_long(lock + 4));
  1543.     if (aino == 0)
  1544.     aino = &unit->rootnode;
  1545.  
  1546.     get_fileinfo (unit, packet, info, aino);
  1547.     if (aino->dir) {
  1548.     put_long(info, 0xFFFFFFFF);
  1549.     } else
  1550.     put_long(info, 0);
  1551. }
  1552.  
  1553. static void action_examine_next(Unit* unit, dpacket packet)
  1554. {
  1555.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  1556.     uaecptr info = GET_PCK_ARG2 (packet) << 2;
  1557.     struct a_inode *aino = 0;
  1558.     ExamineKey *ek;
  1559.     uae_u32 uniq;
  1560.  
  1561.     TRACE((warning_buffer, "ACTION_EXAMINE_NEXT(0x%lx,0x%lx)\n", lock, info));
  1562.     DUMPLOCK(unit, lock);
  1563.  
  1564.     if (lock != 0)
  1565.     aino = lookup_aino (unit, get_long(lock + 4));
  1566.     if (aino == 0)
  1567.     aino = &unit->rootnode;
  1568.  
  1569.     uniq = get_long (info);
  1570.     if (uniq == 0) {
  1571.     write_log ("ExNext called for a file! (Houston?)\n");
  1572.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1573.     PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
  1574.     return;
  1575.     } else if (uniq == 0xFFFFFFFF) {
  1576.     ek = new_exkey(unit, aino);
  1577.     } else
  1578.     ek = lookup_exkey (unit, get_long(info));
  1579.     if (ek == 0) {
  1580.     write_log ("Couldn't find a matching ExKey. Prepare for trouble.\n");
  1581.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1582.     PUT_PCK_RES2 (packet, ERROR_NO_MORE_ENTRIES);
  1583.     return;
  1584.     }
  1585.     put_long(info, ek->uniq);
  1586.     do_examine(unit, packet, ek, info);
  1587. }
  1588.  
  1589. static void do_find (Unit* unit, dpacket packet, int mode, int create, int fallback)
  1590. {
  1591.     uaecptr fh = GET_PCK_ARG1 (packet) << 2;
  1592.     uaecptr lock = GET_PCK_ARG2 (packet) << 2;
  1593.     uaecptr name = GET_PCK_ARG3 (packet) << 2;
  1594.     struct a_inode *aino;
  1595.     Key *k;
  1596.     struct stat st;
  1597.     int fd;
  1598.     int doserr;
  1599.     uae_u32 err;
  1600.     mode_t openmode;
  1601.     int aino_created = 0;
  1602.  
  1603.     TRACE((warning_buffer, "ACTION_FIND_*(0x%lx,0x%lx,\"%s\",%d)\n", fh, lock, bstr (unit, name), mode));
  1604.     DUMPLOCK(unit, lock);
  1605.  
  1606.     aino = find_aino (unit, lock, bstr (unit, name), &err);
  1607.  
  1608.     if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_FOUND)) {
  1609.     /* Whatever it is, we can't handle it. */
  1610.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1611.     PUT_PCK_RES2 (packet, err);
  1612.     return;
  1613.     }
  1614.     if (err == 0) {
  1615.     /* Object exists. */
  1616.     if (aino->dir) {
  1617.         PUT_PCK_RES1 (packet, DOS_FALSE);
  1618.         PUT_PCK_RES2 (packet, ERROR_OBJECT_WRONG_TYPE);
  1619.         return;
  1620.     }
  1621.     if (aino->elock || (create == 2 && aino->shlock > 0)) {
  1622.         PUT_PCK_RES1 (packet, DOS_FALSE);
  1623.         PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
  1624.         return;
  1625.     }
  1626.     if (create == 2 && (aino->amigaos_mode & A_FIBF_DELETE) != 0) {
  1627.         PUT_PCK_RES1 (packet, DOS_FALSE);
  1628.         PUT_PCK_RES2 (packet, ERROR_DELETE_PROTECTED);
  1629.         return;
  1630.     }
  1631.     if (create != 2) {
  1632.         if ((((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0 || unit->ui.readonly)
  1633.         && fallback)
  1634.         {
  1635.         mode &= ~A_FIBF_WRITE;
  1636.         }
  1637.         /* Kick 1.3 doesn't check read and write access bits - maybe it would be
  1638.          * simpler just not to do that either. */
  1639.         if ((mode & A_FIBF_WRITE) != 0 && unit->ui.readonly) {
  1640.         PUT_PCK_RES1 (packet, DOS_FALSE);
  1641.         PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  1642.         return;
  1643.         }
  1644.         if (((mode & aino->amigaos_mode) & A_FIBF_WRITE) != 0
  1645.         || mode == 0)
  1646.         {
  1647.         PUT_PCK_RES1 (packet, DOS_FALSE);
  1648.         PUT_PCK_RES2 (packet, ERROR_WRITE_PROTECTED);
  1649.         return;
  1650.         }
  1651.         if (((mode & aino->amigaos_mode) & A_FIBF_READ) != 0) {
  1652.         PUT_PCK_RES1 (packet, DOS_FALSE);
  1653.         PUT_PCK_RES2 (packet, ERROR_READ_PROTECTED);
  1654.         return;
  1655.         }
  1656.     }
  1657.     } else if (create == 0) {
  1658.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1659.     PUT_PCK_RES2 (packet, err);
  1660.     return;
  1661.     } else {
  1662.     /* Object does not exist. aino points to containing directory. */
  1663.     aino = new_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 1);
  1664.     if (aino == 0) {
  1665.         PUT_PCK_RES1 (packet, DOS_FALSE);
  1666.         PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */
  1667.         return;
  1668.     }
  1669.     aino_created = 1;
  1670.     }
  1671.  
  1672.     prepare_for_open (aino->nname);
  1673.  
  1674.     openmode = (((mode & A_FIBF_READ) == 0 ? O_WRONLY
  1675.          : (mode & A_FIBF_WRITE) == 0 ? O_RDONLY
  1676.          : O_RDWR)
  1677.         | (create ? O_CREAT : 0)
  1678.         | (create == 2 ? O_TRUNC : 0));
  1679.  
  1680.     fd = open (aino->nname, openmode | O_BINARY, 0777);
  1681.  
  1682.     if (fd < 0) {
  1683.     if (aino_created)
  1684.         delete_aino (unit, aino);
  1685.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1686.     PUT_PCK_RES2 (packet, dos_errno());
  1687.     return;
  1688.     }
  1689.     k = new_key (unit);
  1690.     k->fd = fd;
  1691.     k->aino = aino;
  1692.  
  1693.     put_long (fh+36, k->uniq);
  1694.     if (create == 2)
  1695.     aino->elock = 1;
  1696.     else
  1697.     aino->shlock++;
  1698.     de_recycle_aino (unit, aino);
  1699.     PUT_PCK_RES1 (packet, DOS_TRUE);
  1700. }
  1701.  
  1702. static void
  1703. action_find_input(Unit* unit, dpacket packet)
  1704. {
  1705.     do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 0, 1);
  1706. }
  1707.  
  1708. static void
  1709. action_find_output(Unit* unit, dpacket packet)
  1710. {
  1711.     if (unit->ui.readonly) {
  1712.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1713.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  1714.     return;
  1715.     }
  1716.     do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 2, 0);
  1717. }
  1718.  
  1719. static void
  1720. action_find_write(Unit* unit, dpacket packet)
  1721. {
  1722.     if (unit->ui.readonly) {
  1723.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1724.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  1725.     return;
  1726.     }
  1727.     do_find(unit, packet, A_FIBF_READ|A_FIBF_WRITE, 1, 0);
  1728. }
  1729.  
  1730. static void
  1731. action_end(Unit* unit, dpacket packet)
  1732. {
  1733.     Key *k;
  1734.     TRACE((warning_buffer, "ACTION_END(0x%lx)\n", GET_PCK_ARG1 (packet)));
  1735.  
  1736.     k = lookup_key (unit, GET_PCK_ARG1 (packet));
  1737.     if (k != 0) {
  1738.     if (k->aino->elock)
  1739.         k->aino->elock = 0;
  1740.     else
  1741.         k->aino->shlock--;
  1742.     recycle_aino (unit, k->aino);
  1743.     free_key (unit, k);
  1744.     }
  1745.     PUT_PCK_RES1 (packet, DOS_TRUE);
  1746.     PUT_PCK_RES2 (packet, 0);
  1747. }
  1748.  
  1749. static void
  1750. action_read(Unit* unit, dpacket packet)
  1751. {
  1752.     Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
  1753.     uaecptr addr = GET_PCK_ARG2 (packet);
  1754.     long size = (uae_s32)GET_PCK_ARG3 (packet);
  1755.     int actual;
  1756.  
  1757.     if (k == 0) {
  1758.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1759.     /* PUT_PCK_RES2 (packet, EINVAL); */
  1760.     return;
  1761.     }
  1762.     TRACE((warning_buffer, "ACTION_READ(%s,0x%lx,%ld)\n",k->aino->nname,addr,size));
  1763. #ifdef RELY_ON_LOADSEG_DETECTION
  1764.     /* HACK HACK HACK HACK
  1765.      * Try to detect a LoadSeg() */
  1766.     if (k->file_pos == 0 && size >= 4) {
  1767.     unsigned char buf[4];
  1768.     off_t currpos = lseek(k->fd, 0, SEEK_CUR);
  1769.     read(k->fd, buf, 4);
  1770.     lseek(k->fd, currpos, SEEK_SET);
  1771.     if (buf[0] == 0 && buf[1] == 0 && buf[2] == 3 && buf[3] == 0xF3)
  1772.         possible_loadseg();
  1773.     }
  1774. #endif
  1775.     if (valid_address (addr, size)) {
  1776.     uae_u8 *realpt;
  1777.     realpt = get_real_address (addr);
  1778.     actual = read(k->fd, realpt, size);
  1779.  
  1780.     if (actual == 0) {
  1781.         PUT_PCK_RES1 (packet, 0);
  1782.         PUT_PCK_RES2 (packet, 0);
  1783.     } else if (actual < 0) {
  1784.         PUT_PCK_RES1 (packet, 0);
  1785.         PUT_PCK_RES2 (packet, dos_errno());
  1786.     } else {
  1787.         PUT_PCK_RES1 (packet, actual);
  1788.         k->file_pos += actual;
  1789.     }
  1790.     } else {
  1791.     char *buf;
  1792.     sprintf (warning_buffer, "unixfs warning: Bad pointer passed for read: %08x\n", addr);
  1793.     write_log (warning_buffer);
  1794.     /* ugh this is inefficient but easy */
  1795.     buf = (char *)malloc(size);
  1796.     if(!buf) {
  1797.         PUT_PCK_RES1 (packet, -1);
  1798.         PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
  1799.         return;
  1800.     }
  1801.     actual = read(k->fd, buf, size);
  1802.  
  1803.     if (actual < 0) {
  1804.         PUT_PCK_RES1 (packet, 0);
  1805.         PUT_PCK_RES2 (packet, dos_errno());
  1806.     } else {
  1807.         int i;
  1808.         PUT_PCK_RES1 (packet, actual);
  1809.         for(i = 0; i < actual; i++)
  1810.         put_byte(addr + i, buf[i]);
  1811.         k->file_pos += actual;
  1812.     }
  1813.     free(buf);
  1814.     }
  1815. }
  1816.  
  1817. static void
  1818. action_write(Unit* unit, dpacket packet)
  1819. {
  1820.     Key *k = lookup_key (unit, GET_PCK_ARG1 (packet));
  1821.     uaecptr addr = GET_PCK_ARG2 (packet);
  1822.     long size = GET_PCK_ARG3 (packet);
  1823.     char *buf;
  1824.     int i;
  1825.  
  1826.     if (k == 0) {
  1827.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1828.     /* PUT_PCK_RES2 (packet, EINVAL); */
  1829.     return;
  1830.     }
  1831.  
  1832.     TRACE((warning_buffer, "ACTION_WRITE(%s,0x%lx,%ld)\n",k->aino->nname,addr,size));
  1833.  
  1834.     if (unit->ui.readonly) {
  1835.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1836.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  1837.     return;
  1838.     }
  1839.  
  1840.     /* ugh this is inefficient but easy */
  1841.     buf = (char *)malloc(size);
  1842.     if (!buf) {
  1843.     PUT_PCK_RES1 (packet, -1);
  1844.     PUT_PCK_RES2 (packet, ERROR_NO_FREE_STORE);
  1845.     return;
  1846.     }
  1847.  
  1848.     for (i = 0; i < size; i++)
  1849.     buf[i] = get_byte(addr + i);
  1850.  
  1851.     PUT_PCK_RES1 (packet, write(k->fd, buf, size));
  1852.     if (GET_PCK_RES1 (packet) != size)
  1853.     PUT_PCK_RES2 (packet, dos_errno ());
  1854.     if (GET_PCK_RES1 (packet) >= 0)
  1855.     k->file_pos += GET_PCK_RES1 (packet);
  1856.  
  1857.     free(buf);
  1858. }
  1859.  
  1860. static void
  1861. action_seek(Unit* unit, dpacket packet)
  1862. {
  1863.     Key* k = lookup_key (unit, GET_PCK_ARG1 (packet));
  1864.     long pos = (uae_s32)GET_PCK_ARG2 (packet);
  1865.     long mode = (uae_s32)GET_PCK_ARG3 (packet);
  1866.     off_t res;
  1867.     long old;
  1868.     int whence = SEEK_CUR;
  1869.  
  1870.     if (k == 0) {
  1871.     PUT_PCK_RES1 (packet, -1);
  1872.     PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
  1873.     return;
  1874.     }
  1875.  
  1876.     if (mode > 0) whence = SEEK_END;
  1877.     if (mode < 0) whence = SEEK_SET;
  1878.  
  1879.     TRACE((warning_buffer, "ACTION_SEEK(%s,%d,%d)\n", k->aino->nname, pos, mode));
  1880.  
  1881.     old = lseek (k->fd, 0, SEEK_CUR);
  1882.     res = lseek (k->fd, pos, whence);
  1883.  
  1884.     if (-1 == res) {
  1885.     PUT_PCK_RES1 (packet, res);
  1886.     PUT_PCK_RES2 (packet, ERROR_SEEK_ERROR);
  1887.     } else
  1888.     PUT_PCK_RES1 (packet, old);
  1889.     k->file_pos = res;
  1890. }
  1891.  
  1892. static void
  1893. action_set_protect(Unit* unit, dpacket packet)
  1894. {
  1895.     uaecptr lock = GET_PCK_ARG2 (packet) << 2;
  1896.     uaecptr name = GET_PCK_ARG3 (packet) << 2;
  1897.     uae_u32 mask = GET_PCK_ARG4 (packet);
  1898.     mode_t mode;
  1899.     struct a_inode *a;
  1900.     uae_u32 err;
  1901.  
  1902.     TRACE((warning_buffer, "ACTION_SET_PROTECT(0x%lx,\"%s\",0x%lx)\n", lock, bstr (unit, name), mask));
  1903.  
  1904.     if (unit->ui.readonly) {
  1905.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1906.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  1907.     return;
  1908.     }
  1909.  
  1910.     a = find_aino (unit, lock, bstr (unit, name), &err);
  1911.     if (err != 0) {
  1912.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1913.     PUT_PCK_RES2 (packet, err);
  1914.     return;
  1915.     }
  1916.  
  1917.     err = set_file_attrs (a, mask);
  1918.     if (err != 0) {
  1919.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1920.     PUT_PCK_RES2 (packet, err);
  1921.     } else {
  1922.     PUT_PCK_RES1 (packet, DOS_TRUE);
  1923.     }
  1924. }
  1925.  
  1926. static void
  1927. action_same_lock(Unit* unit, dpacket packet)
  1928. {
  1929.     uaecptr lock1 = GET_PCK_ARG1 (packet) << 2;
  1930.     uaecptr lock2 = GET_PCK_ARG2 (packet) << 2;
  1931.  
  1932.     TRACE((warning_buffer, "ACTION_SAME_LOCK(0x%lx,0x%lx)\n",lock1,lock2));
  1933.     DUMPLOCK(unit, lock1); DUMPLOCK(unit, lock2);
  1934.  
  1935.     if (!lock1 || !lock2) {
  1936.     PUT_PCK_RES1 (packet, lock1 == lock2 ? DOS_TRUE : DOS_FALSE);
  1937.     } else {
  1938.     PUT_PCK_RES1 (packet, get_long (lock1 + 4) == get_long (lock2 + 4) ? DOS_TRUE : DOS_FALSE);
  1939.     }
  1940. }
  1941.  
  1942. static void
  1943. action_parent(Unit* unit, dpacket packet)
  1944. {
  1945.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  1946.     struct a_inode *a, *olda;
  1947.  
  1948.     TRACE((warning_buffer, "ACTION_PARENT(0x%lx)\n",lock));
  1949.  
  1950.     if (!lock) {
  1951.     PUT_PCK_RES1 (packet, 0);
  1952.     PUT_PCK_RES2 (packet, 0);
  1953.     return;
  1954.     }
  1955.  
  1956.     olda = lookup_aino (unit, get_long(lock + 4));
  1957.     if (olda == 0) {
  1958.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1959.     PUT_PCK_RES2 (packet, ERROR_INVALID_LOCK);
  1960.     return;
  1961.     }
  1962.  
  1963.     if (olda->parent == 0) {
  1964.     PUT_PCK_RES1 (packet, 0);
  1965.     PUT_PCK_RES2 (packet, 0);
  1966.     return;
  1967.     }
  1968.     if (olda->parent->elock) {
  1969.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1970.     PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
  1971.     return;
  1972.     }
  1973.     olda->parent->shlock++;
  1974.     de_recycle_aino (unit, olda->parent);
  1975.     PUT_PCK_RES1 (packet, make_lock (unit, olda->parent->uniq, -2) >> 2);
  1976. }
  1977.  
  1978. static void
  1979. action_create_dir(Unit* unit, dpacket packet)
  1980. {
  1981.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  1982.     uaecptr name = GET_PCK_ARG2 (packet) << 2;
  1983.     struct a_inode *aino;
  1984.     uae_u32 err;
  1985.  
  1986.     TRACE((warning_buffer, "ACTION_CREATE_DIR(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
  1987.  
  1988.     if (unit->ui.readonly) {
  1989.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1990.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  1991.     return;
  1992.     }
  1993.  
  1994.     aino = find_aino (unit, lock, bstr (unit, name), &err);
  1995.     if (aino == 0 || (err != 0 && err != ERROR_OBJECT_NOT_FOUND)) {
  1996.     PUT_PCK_RES1 (packet, DOS_FALSE);
  1997.     PUT_PCK_RES2 (packet, err);
  1998.     return;
  1999.     }
  2000.     if (err == 0) {
  2001.     /* Object exists. */
  2002.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2003.     PUT_PCK_RES2 (packet, ERROR_OBJECT_EXISTS);
  2004.     return;
  2005.     }
  2006.     /* Object does not exist. aino points to containing directory. */
  2007.     aino = new_child_aino (unit, aino, my_strdup (bstr_cut (unit, name)), 2);
  2008.     if (aino == 0) {
  2009.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2010.     PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */
  2011.     return;
  2012.     }
  2013.  
  2014.     if (mkdir (aino->nname, 0777) == -1) {
  2015.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2016.     PUT_PCK_RES2 (packet, dos_errno());
  2017.     return;
  2018.     }
  2019.     aino->shlock = 1;
  2020.     de_recycle_aino (unit, aino);
  2021.     PUT_PCK_RES1 (packet, make_lock (unit, aino->uniq, -2) >> 2);
  2022. }
  2023.  
  2024. static void
  2025. action_examine_fh(Unit* unit, dpacket packet)
  2026. {
  2027.     Key *k;
  2028.     ExamineKey* ek;
  2029.     struct a_inode *aino = 0;
  2030.     uaecptr info = GET_PCK_ARG2 (packet) << 2;
  2031.  
  2032.     TRACE((warning_buffer, "ACTION_EXAMINE_FH(0x%lx,0x%lx)\n", GET_PCK_ARG1 (packet), GET_PCK_ARG2 (packet) ));
  2033.  
  2034.     k = lookup_key (unit, GET_PCK_ARG1 (packet));
  2035.     if (k != 0)
  2036.     aino = k->aino;
  2037.     if (aino == 0)
  2038.     aino = &unit->rootnode;
  2039.  
  2040.     get_fileinfo (unit, packet, info, aino);
  2041.     if (aino->dir)
  2042.     put_long(info, 0xFFFFFFFF);
  2043.     else
  2044.     put_long(info, 0);
  2045. }
  2046.  
  2047. /* For a nice example of just how contradictory documentation can be, see the
  2048.  * Autodoc for DOS:SetFileSize and the Packets.txt description of this packet...
  2049.  * This implementation tries to mimic the behaviour of the Kick 3.1 ramdisk
  2050.  * (which seems to match the Autodoc description). */
  2051. static void
  2052. action_set_file_size(Unit* unit, dpacket packet)
  2053. {
  2054.     int error = 0;
  2055.     char chunk = 0;
  2056.     Key *k, *k1;
  2057.     off_t offset = GET_PCK_ARG2 (packet);
  2058.     long mode = (uae_s32)GET_PCK_ARG3 (packet);
  2059.     int whence = SEEK_CUR;
  2060.     
  2061.     if (mode > 0) whence = SEEK_END;
  2062.     if (mode < 0) whence = SEEK_SET;
  2063.  
  2064.     TRACE((warning_buffer, "ACTION_SET_FILE_SIZE(0x%lx, %d, 0x%x)\n", GET_PCK_ARG1 (packet), offset, mode));
  2065.  
  2066.     k = lookup_key (unit, GET_PCK_ARG1 (packet));
  2067.     if (k == 0) {
  2068.     PUT_PCK_RES1 (packet, DOS_TRUE);
  2069.     PUT_PCK_RES2 (packet, ERROR_OBJECT_NOT_FOUND);
  2070.     return;
  2071.     }
  2072.  
  2073.     /* If any open files have file pointers beyond this size, truncate only
  2074.      * so far that these pointers do not become invalid.  */
  2075.     for (k1 = unit->keys; k1; k1 = k1->next) {
  2076.     if (k != k1 && k->aino == k1->aino) {
  2077.         if (k1->file_pos > offset)
  2078.         offset = k1->file_pos;
  2079.     }
  2080.     }
  2081.  
  2082.     /* Write one then truncate: that should give the right size in all cases.  */
  2083.     offset = lseek (k->fd, offset, whence);
  2084.     write (k->fd, /* whatever */(char *)&k1, 1);
  2085.     if (k->file_pos > offset)
  2086.     k->file_pos = offset;
  2087.     lseek (k->fd, k->file_pos, SEEK_SET);
  2088.  
  2089.     if (truncate (k->aino->nname, k->file_pos) == -1) {
  2090.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2091.     PUT_PCK_RES2 (packet, dos_errno ());
  2092.     return;
  2093.     }
  2094.  
  2095.     PUT_PCK_RES1 (packet, offset);
  2096.     PUT_PCK_RES2 (packet, 0);
  2097. }
  2098.  
  2099. static void
  2100. action_delete_object(Unit* unit, dpacket packet)
  2101. {
  2102.     uaecptr lock = GET_PCK_ARG1 (packet) << 2;
  2103.     uaecptr name = GET_PCK_ARG2 (packet) << 2;
  2104.     struct a_inode *a;
  2105.     uae_u32 err;
  2106.  
  2107.     TRACE((warning_buffer, "ACTION_DELETE_OBJECT(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
  2108.  
  2109.     if (unit->ui.readonly) {
  2110.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2111.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  2112.     return;
  2113.     }
  2114.  
  2115.     a = find_aino (unit, lock, bstr (unit, name), &err);
  2116.  
  2117.     if (err != 0) {
  2118.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2119.     PUT_PCK_RES2 (packet, err);
  2120.     return;
  2121.     }
  2122.     if (a->shlock > 0 || a->elock) {
  2123.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2124.     PUT_PCK_RES2 (packet, ERROR_OBJECT_IN_USE);
  2125.     return;
  2126.     }
  2127.     if (a->dir) {
  2128.     if (rmdir (a->nname) == -1) {
  2129.         PUT_PCK_RES1 (packet, DOS_FALSE);
  2130.         PUT_PCK_RES2 (packet, dos_errno());
  2131.         return;
  2132.     }
  2133.     } else {
  2134.     if (unlink (a->nname) == -1) {
  2135.         PUT_PCK_RES1 (packet, DOS_FALSE);
  2136.         PUT_PCK_RES2 (packet, dos_errno());
  2137.         return;
  2138.     }
  2139.     }
  2140.     if (a->child != 0) {
  2141.     write_log ("Serious error in action_delete_object.\n");
  2142.     } else {
  2143.     delete_aino (unit, a);
  2144.     }
  2145.     PUT_PCK_RES1 (packet, DOS_TRUE);
  2146. }
  2147.  
  2148. static void
  2149. action_set_date(Unit* unit, dpacket packet)
  2150. {
  2151.     uaecptr lock = GET_PCK_ARG2 (packet) << 2;
  2152.     uaecptr name = GET_PCK_ARG3 (packet) << 2;
  2153.     uaecptr date = GET_PCK_ARG4 (packet);
  2154.     struct a_inode *a;
  2155.     struct utimbuf ut;
  2156.     uae_u32 err;
  2157.  
  2158.     TRACE((warning_buffer, "ACTION_SET_DATE(0x%lx,\"%s\")\n", lock, bstr (unit, name)));
  2159.  
  2160.     if(unit->ui.readonly) {
  2161.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2162.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  2163.     return;
  2164.     }
  2165.  
  2166.     ut.actime = ut.modtime = put_time(get_long(date),get_long(date+4),get_long(date+8));
  2167.     a = find_aino (unit, lock, bstr (unit, name), &err);
  2168.     if (err == 0 && utime (a->nname, &ut) == -1)
  2169.     err = dos_errno ();
  2170.     if (err != 0) {
  2171.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2172.     PUT_PCK_RES2 (packet, err);
  2173.     } else
  2174.     PUT_PCK_RES1 (packet, DOS_TRUE);
  2175. }
  2176.  
  2177. static void
  2178. action_rename_object(Unit* unit, dpacket packet)
  2179. {
  2180.     uaecptr lock1 = GET_PCK_ARG1 (packet) << 2;
  2181.     uaecptr name1 = GET_PCK_ARG2 (packet) << 2;
  2182.     uaecptr lock2 = GET_PCK_ARG3 (packet) << 2;
  2183.     uaecptr name2 = GET_PCK_ARG4 (packet) << 2;
  2184.     struct a_inode *a1, *a2;
  2185.     uae_u32 err1, err2;
  2186.  
  2187.     TRACE((warning_buffer, "ACTION_RENAME_OBJECT(0x%lx,\"%s\",", lock1, bstr (unit, name1)));
  2188.     TRACE((warning_buffer, "0x%lx,\"%s\")\n", lock2, bstr (unit, name2)));
  2189.  
  2190.     if(unit->ui.readonly) {
  2191.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2192.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  2193.     return;
  2194.     }
  2195.  
  2196.     a1 = find_aino (unit, lock1, bstr (unit, name1), &err1);
  2197.     if (err1 != 0) {
  2198.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2199.     PUT_PCK_RES2 (packet, err1);
  2200.     return;
  2201.     }
  2202.     a2 = find_aino (unit, lock2, bstr (unit, name2), &err2);
  2203.     if (a2 == 0 || err2 != ERROR_OBJECT_NOT_FOUND) {
  2204.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2205.     PUT_PCK_RES2 (packet, err2 == 0 ? ERROR_OBJECT_EXISTS : err2);
  2206.     return;
  2207.     }
  2208.     /* Object does not exist. aino points to containing directory. */
  2209.     a2 = new_child_aino (unit, a2, my_strdup (bstr_cut (unit, name2)), a1->dir ? 2 : 1);
  2210.     if (a2 == 0) {
  2211.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2212.     PUT_PCK_RES2 (packet, ERROR_DISK_FULL); /* best we can do */
  2213.     return;
  2214.     }
  2215.  
  2216.     /* @@@ what should we do if there are locks on a1? */
  2217.     if(-1 == rename(a1->nname, a2->nname)) {
  2218.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2219.     PUT_PCK_RES2 (packet, dos_errno());
  2220.     return;
  2221.     }
  2222.     move_aino_children (unit, a1, a2);
  2223.     delete_aino (unit, a1);
  2224.     PUT_PCK_RES1 (packet, DOS_TRUE);
  2225. }
  2226.  
  2227. static void
  2228. action_current_volume(Unit* unit, dpacket packet)
  2229. {
  2230.     PUT_PCK_RES1 (packet, unit->volume >> 2);
  2231. }
  2232.  
  2233. static void
  2234. action_rename_disk(Unit* unit, dpacket packet)
  2235. {
  2236.     uaecptr name = GET_PCK_ARG1 (packet) << 2;
  2237.     int i;
  2238.     int namelen;
  2239.  
  2240.     TRACE((warning_buffer, "ACTION_RENAME_DISK(\"%s\")\n", bstr (unit, name)));
  2241.  
  2242.     if(unit->ui.readonly) {
  2243.     PUT_PCK_RES1 (packet, DOS_FALSE);
  2244.     PUT_PCK_RES2 (packet, ERROR_DISK_WRITE_PROTECTED);
  2245.     return;
  2246.     }
  2247.  
  2248.     /* get volume name */
  2249.     namelen = get_byte (name); name++;
  2250.     free (unit->ui.volname);
  2251.     unit->ui.volname = (char *) xmalloc (namelen + 1);
  2252.     for(i = 0; i < namelen; i++, name++)
  2253.     unit->ui.volname[i] = get_byte (name);
  2254.     unit->ui.volname[i] = 0;
  2255.  
  2256.     put_byte (unit->volume + 44, namelen);
  2257.     for(i = 0; i < namelen; i++)
  2258.     put_byte (unit->volume + 45 + i, unit->ui.volname[i]);
  2259.  
  2260.     PUT_PCK_RES1 (packet, DOS_TRUE);
  2261. }
  2262.  
  2263. static void
  2264. action_is_filesystem(Unit* unit, dpacket packet)
  2265. {
  2266.     PUT_PCK_RES1 (packet, DOS_TRUE);
  2267. }
  2268.  
  2269. static void
  2270. action_flush(Unit* unit, dpacket packet)
  2271. {
  2272.     /* sync(); */ /* pretty drastic, eh */
  2273.     PUT_PCK_RES1 (packet, DOS_TRUE);
  2274. }
  2275.  
  2276. /* We don't want multiple interrupts to be active at the same time. I don't
  2277.  * know whether AmigaOS takes care of that, but this does. */
  2278. static uae_sem_t singlethread_int_sem;
  2279.  
  2280. static uae_u32 exter_int_helper (void)
  2281. {
  2282.     static int unit_no;
  2283.  
  2284.     switch (m68k_dreg (regs, 0)) {
  2285.      case 0:
  2286.     /* Determine whether a given EXTER interrupt is for us. */
  2287.     if (uae_int_requested) {
  2288.         if (uae_sem_trywait (&singlethread_int_sem) != 0)
  2289.         /* Pretend it isn't for us. We might get it again later. */
  2290.         return 0;
  2291.         /* Clear the interrupt flag _before_ we do any processing.
  2292.          * That way, we can get too many interrupts, but never not
  2293.          * enough. */
  2294.         uae_int_requested = 0;
  2295.         unit_no = 0;
  2296.         return 1;
  2297.     }
  2298.     return 0;
  2299.      case 1:
  2300.     /* Release a message_lock. This is called as soon as the message is
  2301.      * received by the assembly code. We use the opportunity to check
  2302.      * whether we have some locks that we can give back to the assembler
  2303.      * code.
  2304.      * Note that this is called from the main loop, unlike the other cases
  2305.      * in this switch statement which are called from the interrupt handler.
  2306.      */
  2307.     {
  2308.         Unit *unit = find_unit (m68k_areg (regs, 5));
  2309.         unit->cmds_complete = unit->cmds_acked;
  2310.         while (comm_pipe_has_data (unit->ui.back_pipe)) {
  2311.         uaecptr locks, lockend;
  2312.         locks = read_comm_pipe_int_blocking (unit->ui.back_pipe);
  2313.         lockend = locks;
  2314.         while (get_long (lockend) != 0)
  2315.             lockend = get_long (lockend);
  2316.         put_long (lockend, get_long (m68k_areg (regs, 3)));
  2317.         put_long (m68k_areg (regs, 3), locks);
  2318.         }
  2319.     }
  2320.     break;
  2321.      case 2:
  2322.     /* Find some unit that needs a message sent, and return its port,
  2323.      * or zero if all are done.
  2324.      * Take care not to dereference self for units that didn't have their
  2325.      * startup packet sent. */
  2326.     for (;;) {
  2327.         if (unit_no >= num_units)
  2328.         return 0;
  2329.         if (ui[unit_no].self != 0
  2330.         && ui[unit_no].self->cmds_acked == ui[unit_no].self->cmds_complete
  2331.         && ui[unit_no].self->cmds_acked != ui[unit_no].self->cmds_sent)
  2332.         break;
  2333.         unit_no++;
  2334.     }
  2335.     ui[unit_no].self->cmds_acked = ui[unit_no].self->cmds_sent;
  2336.     return ui[unit_no++].self->port;
  2337.  
  2338.      case 3:
  2339.     /* Look up a message for a port. */
  2340.     {
  2341.         Unit *unit = find_unit (m68k_areg (regs, 2));
  2342.         return unit->dummy_message;
  2343.     }
  2344.     break;
  2345.      case 4:
  2346.     /* Exit the interrupt, and release the single-threading lock. */
  2347.     uae_sem_post (&singlethread_int_sem);
  2348.     break;
  2349.  
  2350.      default:
  2351.     write_log ("Shouldn't happen in exter_int_helper.\n");
  2352.     break;
  2353.     }
  2354.     return 0;
  2355. }
  2356.  
  2357. static int handle_packet (Unit *unit, dpacket pck)
  2358. {
  2359.     uae_s32 type = GET_PCK_TYPE (pck);
  2360.     PUT_PCK_RES2 (pck, 0);
  2361.     switch (type) {
  2362.      case ACTION_LOCATE_OBJECT: action_lock(unit, pck); break;
  2363.      case ACTION_FREE_LOCK: action_free_lock(unit, pck); break;
  2364.      case ACTION_COPY_DIR: action_dup_lock(unit, pck); break;
  2365.      case ACTION_DISK_INFO: action_disk_info(unit, pck); break;
  2366.      case ACTION_INFO: action_info(unit, pck); break;
  2367.      case ACTION_EXAMINE_OBJECT: action_examine_object(unit, pck); break;
  2368.      case ACTION_EXAMINE_NEXT: action_examine_next(unit, pck); break;
  2369.      case ACTION_FIND_INPUT: action_find_input(unit, pck); break;
  2370.      case ACTION_FIND_WRITE: action_find_write(unit, pck); break;
  2371.      case ACTION_FIND_OUTPUT: action_find_output(unit, pck); break;
  2372.      case ACTION_END: action_end(unit, pck); break;
  2373.      case ACTION_READ: action_read(unit, pck); break;
  2374.      case ACTION_WRITE: action_write(unit, pck); break;
  2375.      case ACTION_SEEK: action_seek(unit, pck); break;
  2376.      case ACTION_SET_PROTECT: action_set_protect(unit, pck); break;
  2377.      case ACTION_SAME_LOCK: action_same_lock(unit, pck); break;
  2378.      case ACTION_PARENT: action_parent(unit, pck); break;
  2379.      case ACTION_CREATE_DIR: action_create_dir(unit, pck); break;
  2380.      case ACTION_DELETE_OBJECT: action_delete_object(unit, pck); break;
  2381.      case ACTION_RENAME_OBJECT: action_rename_object(unit, pck); break;
  2382.      case ACTION_SET_DATE: action_set_date(unit, pck); break;
  2383.      case ACTION_CURRENT_VOLUME: action_current_volume(unit, pck); break;
  2384.      case ACTION_RENAME_DISK: action_rename_disk(unit, pck); break;
  2385.      case ACTION_IS_FILESYSTEM: action_is_filesystem(unit, pck); break;
  2386.      case ACTION_FLUSH: action_flush(unit, pck); break;
  2387.  
  2388.      /* 2.0+ packet types */
  2389.      case ACTION_SET_FILE_SIZE: action_set_file_size(unit, pck); break;
  2390.      case ACTION_EXAMINE_FH: action_examine_fh(unit, pck); break;
  2391.  
  2392.      /* unsupported packets */
  2393.      case ACTION_LOCK_RECORD:
  2394.      case ACTION_FREE_RECORD:
  2395.      case ACTION_CHANGE_MODE:
  2396.      case ACTION_FH_FROM_LOCK:
  2397.      case ACTION_COPY_DIR_FH:
  2398.      case ACTION_PARENT_FH:
  2399.      case ACTION_EXAMINE_ALL:
  2400.      case ACTION_MAKE_LINK:
  2401.      case ACTION_READ_LINK:
  2402.      case ACTION_FORMAT:
  2403.      case ACTION_ADD_NOTIFY:
  2404.      case ACTION_REMOVE_NOTIFY:
  2405.      default:
  2406.     TRACE((warning_buffer, "*** UNSUPPORTED PACKET %ld\n", type));
  2407.     return 0;
  2408.     }
  2409.     return 1;
  2410. }
  2411.  
  2412. #ifdef UAE_FILESYS_THREADS
  2413. static void *filesys_penguin (void *unit_v)
  2414. {
  2415.     UnitInfo *ui = (UnitInfo *)unit_v;
  2416.     for (;;) {
  2417.     uae_u8 *pck;
  2418.     uae_u8 *msg;
  2419.     uae_u32 morelocks;
  2420.     int i;
  2421.  
  2422.     pck = (uae_u8 *)read_comm_pipe_pvoid_blocking (ui->unit_pipe);
  2423.     msg = (uae_u8 *)read_comm_pipe_pvoid_blocking (ui->unit_pipe);
  2424.     morelocks = (uae_u32)read_comm_pipe_int_blocking (ui->unit_pipe);
  2425.  
  2426.     if (ui->self->reset_state == FS_GO_DOWN) {
  2427.         if (pck != 0)
  2428.         continue;
  2429.         /* Death message received. */
  2430.         uae_sem_post (&ui->self->reset_sync_sem);
  2431.         /* No more messages should arrive until we restart. */
  2432.         continue;
  2433.     }
  2434.  
  2435.     put_long (get_long (morelocks), get_long (ui->self->locklist));
  2436.     put_long (ui->self->locklist, morelocks);
  2437.     if (! handle_packet (ui->self, pck)) {
  2438.         PUT_PCK_RES1 (pck, DOS_FALSE);
  2439.         PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN);
  2440.     }
  2441.     /* Mark the packet as processed for the list scan in the assembly code. */
  2442.     do_put_mem_long ((uae_u32 *)(msg + 4), -1);
  2443.     /* Acquire the message lock, so that we know we can safely send the
  2444.      * message. */
  2445.     ui->self->cmds_sent++;
  2446.     /* The message is sent by our interrupt handler, so make sure an interrupt
  2447.      * happens. */
  2448.     uae_int_requested = 1;
  2449.     /* Send back the locks. */
  2450.     if (get_long (ui->self->locklist) != 0)
  2451.         write_comm_pipe_int (ui->back_pipe, (int)(get_long(ui->self->locklist)), 0);
  2452.     put_long (ui->self->locklist, 0);
  2453.     }
  2454.     return 0;
  2455. }
  2456. #endif
  2457.  
  2458. /* Talk about spaghetti code... */
  2459. static uae_u32 filesys_handler(void)
  2460. {
  2461.     Unit *unit = find_unit (m68k_areg (regs, 5));
  2462.     uaecptr packet_addr = m68k_dreg (regs, 3);
  2463.     uaecptr message_addr = m68k_areg (regs, 4);
  2464.     uae_u8 *pck;
  2465.     uae_u8 *msg;
  2466.     if (! valid_address (packet_addr, 36) || ! valid_address (message_addr, 14)) {
  2467.     write_log ("Bad address passed for packet.\n");
  2468.     goto error2;
  2469.     }
  2470.     pck = get_real_address (packet_addr);
  2471.     msg = get_real_address (message_addr);
  2472.  
  2473.     if (unit->reset_state == FS_GO_DOWN)
  2474.     /* You might as well queue it, if you live long enough */
  2475.     return 1;
  2476.  
  2477.     do_put_mem_long ((uae_u32 *)(msg + 4), -1);
  2478.     if (!unit || !unit->volume) {
  2479.     write_log ("Filesystem was not initialized.\n");
  2480.     goto error;
  2481.     }
  2482. #ifdef UAE_FILESYS_THREADS
  2483.     {
  2484.     /* Get two more locks and hand them over to the other thread. */
  2485.     uae_u32 morelocks;
  2486.     morelocks = get_long (m68k_areg (regs, 3));
  2487.     put_long (m68k_areg (regs, 3), get_long (get_long (morelocks)));
  2488.     put_long (get_long (morelocks), 0);
  2489.  
  2490.     /* The packet wasn't processed yet. */
  2491.     do_put_mem_long ((uae_u32 *)(msg + 4), 0);
  2492.     write_comm_pipe_pvoid (unit->ui.unit_pipe, (void *)pck, 0);
  2493.     write_comm_pipe_pvoid (unit->ui.unit_pipe, (void *)msg, 0);
  2494.     write_comm_pipe_int (unit->ui.unit_pipe, (int)morelocks, 1);
  2495.     /* Don't reply yet. */
  2496.     return 1;
  2497.     }
  2498. #endif
  2499.  
  2500.     if (! handle_packet (unit, pck)) {
  2501.     error:
  2502.     PUT_PCK_RES1 (pck, DOS_FALSE);
  2503.     PUT_PCK_RES2 (pck, ERROR_ACTION_NOT_KNOWN);
  2504.     }
  2505.     TRACE((warning_buffer, "reply: %8lx, %ld\n", GET_PCK_RES1 (pck), GET_PCK_RES2 (pck)));
  2506.  
  2507.     error2:
  2508.  
  2509.     return 0;
  2510. }
  2511.  
  2512. void filesys_reset (void)
  2513. {
  2514.     Unit *u, *u1;
  2515.     int i;
  2516.  
  2517.     for (i = 0; i < num_units; i++) {
  2518.     ui[i].self = 0;
  2519.     }
  2520.  
  2521.     for(u = units; u; u = u1) {
  2522.     u1 = u->next;
  2523.     free (u);
  2524.     }
  2525.     unit_num = 0;
  2526.     units = 0;
  2527. }
  2528.  
  2529. void filesys_prepare_reset (void)
  2530. {
  2531.     Unit *u, *u1;
  2532.     int i;
  2533.  
  2534. #ifdef UAE_FILESYS_THREADS
  2535.     for (i = 0; i < num_units; i++) {
  2536.     if (ui[i].self != 0) {
  2537.         uae_sem_init (&ui[i].self->reset_sync_sem, 0, 0);
  2538.         ui[i].self->reset_state = FS_GO_DOWN;
  2539.         /* send death message */
  2540.         write_comm_pipe_int (ui[i].unit_pipe, 0, 0);
  2541.         write_comm_pipe_int (ui[i].unit_pipe, 0, 0);
  2542.         write_comm_pipe_int (ui[i].unit_pipe, 0, 1);
  2543.         uae_sem_wait (&ui[i].self->reset_sync_sem);
  2544.     }
  2545.     }
  2546. #endif
  2547.     u = units;
  2548.     while (u != 0) {
  2549.     while (u->rootnode.next != &u->rootnode) {
  2550.         struct a_inode *a = u->rootnode.next;
  2551.         u->rootnode.next = a->next;
  2552.         free (a->nname);
  2553.         free (a->aname);
  2554.         free (a);
  2555.     }
  2556.     u = u->next;
  2557.     }
  2558. }
  2559.  
  2560. static uae_u32 filesys_diagentry(void)
  2561. {
  2562.     uaecptr resaddr = m68k_areg(regs, 2) + 0x10;
  2563.  
  2564.     TRACE ((warning_buffer, "filesystem: diagentry called\n"));
  2565.  
  2566.     filesys_configdev = m68k_areg(regs, 3);
  2567.  
  2568.     do_put_mem_long ((uae_u32 *)(filesysory + 0x2100), EXPANSION_explibname);
  2569.     do_put_mem_long ((uae_u32 *)(filesysory + 0x2104), filesys_configdev);
  2570.     do_put_mem_long ((uae_u32 *)(filesysory + 0x2108), EXPANSION_doslibname);
  2571.     do_put_mem_long ((uae_u32 *)(filesysory + 0x210c), num_units);
  2572.  
  2573.     uae_sem_init (&singlethread_int_sem, 0, 1);
  2574.     if (ROM_hardfile_resid != 0) {
  2575.     /* Build a struct Resident. This will set up and initialize
  2576.      * the uae.device */
  2577.     put_word(resaddr + 0x0, 0x4AFC);
  2578.     put_long(resaddr + 0x2, resaddr);
  2579.     put_long(resaddr + 0x6, resaddr + 0x1A); /* Continue scan here */
  2580.     put_word(resaddr + 0xA, 0x8101); /* RTF_AUTOINIT|RTF_COLDSTART; Version 1 */
  2581.     put_word(resaddr + 0xC, 0x0305); /* NT_DEVICE; pri 05 */
  2582.     put_long(resaddr + 0xE, ROM_hardfile_resname);
  2583.     put_long(resaddr + 0x12, ROM_hardfile_resid);
  2584.     put_long(resaddr + 0x16, ROM_hardfile_init); /* calls filesys_init */
  2585.     }
  2586.     resaddr += 0x1A;
  2587.  
  2588.     filesys_reset ();
  2589.     /* The good thing about this function is that it always gets called
  2590.      * when we boot. So we could put all sorts of stuff that wants to be done
  2591.      * here. */
  2592.  
  2593.     return 1;
  2594. }
  2595.  
  2596. /* Remember a pointer AmigaOS gave us so we can later use it to identify
  2597.  * which unit a given startup message belongs to.  */
  2598. static uae_u32 filesys_dev_remember(void)
  2599. {
  2600.     int unit_no = m68k_dreg (regs, 6);
  2601.     uaecptr devicenode = m68k_areg (regs, 3);
  2602.  
  2603.     ui[unit_no].startup = get_long (devicenode + 28);
  2604.     return devicenode;
  2605. }
  2606.  
  2607. /* Fill in per-unit fields of a parampacket */
  2608. static uae_u32 filesys_dev_storeinfo(void)
  2609. {
  2610.     int unit_no = m68k_dreg (regs, 6);
  2611.     uaecptr parmpacket = m68k_areg (regs, 0);
  2612.     int is_hardfile = ui[unit_no].volname == 0;
  2613.  
  2614.     put_long (parmpacket, ui[unit_no].devname_amiga);
  2615.     put_long (parmpacket + 4, is_hardfile ? ROM_hardfile_resname : fsdevname);
  2616.     put_long (parmpacket + 8, ui[unit_no].devno);
  2617.     put_long (parmpacket + 12, 0); /* Device flags */
  2618.     put_long (parmpacket + 16, 16); /* Env. size */
  2619.     put_long (parmpacket + 20, 128); /* 512 bytes per block */
  2620.     put_long (parmpacket + 24, 0); /* unused */
  2621.     put_long (parmpacket + 28, ui[unit_no].hf.surfaces); /* heads */
  2622.     put_long (parmpacket + 32, 0); /* unused */
  2623.     put_long (parmpacket + 36, ui[unit_no].hf.secspertrack); /* sectors per track */
  2624.     put_long (parmpacket + 40, ui[unit_no].hf.reservedblocks); /* reserved blocks */
  2625.     put_long (parmpacket + 44, 0); /* unused */
  2626.     put_long (parmpacket + 48, 0); /* interleave */
  2627.     put_long (parmpacket + 52, 0); /* lowCyl */
  2628.     put_long (parmpacket + 56, ui[unit_no].hf.nrcyls - 1); /* hiCyl */
  2629.     put_long (parmpacket + 60, 0); /* Number of buffers */
  2630.     put_long (parmpacket + 64, 0); /* Buffer mem type */
  2631.     put_long (parmpacket + 68, 0x7FFFFFFF); /* largest transfer */
  2632.     put_long (parmpacket + 72, ~1); /* addMask (?) */
  2633.     put_long (parmpacket + 76, (uae_u32)-1); /* bootPri */
  2634.     put_long (parmpacket + 80, 0x444f5300); /* DOS\0 */
  2635.     put_long (parmpacket + 84, 0); /* pad */
  2636.  
  2637.     return is_hardfile;
  2638. }
  2639.  
  2640. /* Called exactly once, at the time we know that we are actually going
  2641.  * to run the emulator. */
  2642. void filesys_start_threads (void)
  2643. {
  2644.     int i;
  2645.     for (i = 0; i < num_units; i++) {
  2646.     int is_hardfile = ui[i].volname == 0;
  2647.     ui[i].unit_pipe = 0;
  2648. #ifdef UAE_FILESYS_THREADS
  2649.     if (!is_hardfile) {
  2650.         ui[i].unit_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe));
  2651.         ui[i].back_pipe = (smp_comm_pipe *)xmalloc (sizeof (smp_comm_pipe));
  2652.         init_comm_pipe (ui[i].unit_pipe, 50, 3);
  2653.         init_comm_pipe (ui[i].back_pipe, 50, 1);
  2654.         start_penguin (filesys_penguin, (void *)(ui + i), &ui[i].tid);
  2655.     }
  2656. #endif
  2657.     }
  2658. }
  2659.  
  2660. void filesys_install (void)
  2661. {
  2662.     int i;
  2663.     uaecptr loop;
  2664.  
  2665.     TRACE ((warning_buffer, "Installing filesystem\n"));
  2666.  
  2667.     ROM_filesys_resname = ds("UAEunixfs.resource");
  2668.     ROM_filesys_resid = ds("UAE unixfs 0.4");
  2669.  
  2670.     fsdevname = ds("uae.device"); /* does not really exist */
  2671.  
  2672.     for(i = 0; i < num_units; i++) {
  2673.     ui[i].devno = get_new_device(&ui[i].devname, &ui[i].devname_amiga);
  2674.     }
  2675.  
  2676.     ROM_filesys_diagentry = here();
  2677.     calltrap (deftrap(filesys_diagentry)); dw(RTS);
  2678.  
  2679.     loop = here ();
  2680.     /* Special trap for the assembly make_dev routine */
  2681.     org(0xF0FF20);
  2682.     calltrap (deftrap (filesys_dev_remember));
  2683.     dw(RTS);
  2684.  
  2685.     org(0xF0FF28);
  2686.     calltrap (deftrap (filesys_dev_storeinfo));
  2687.     dw(RTS);
  2688.  
  2689.     org(0xF0FF30);
  2690.     calltrap (deftrap (filesys_handler));
  2691.     dw(RTS);
  2692.  
  2693.     org(0xF0FF40);
  2694.     calltrap (deftrap (startup_handler));
  2695.     dw(RTS);
  2696.  
  2697.     org(0xF0FF50);
  2698.     calltrap (deftrap (exter_int_helper));
  2699.     dw(RTS);
  2700.  
  2701.     org(0xF0FF70);
  2702.     calltrap (deftrap (mousehack_helper));
  2703.     dw(RTS);
  2704.  
  2705.     org (loop);
  2706. }
  2707.  
  2708. void filesys_install_code (void)
  2709. {
  2710.     align(4);
  2711.  
  2712.     /* The last offset comes from the code itself, look for it near the top. */
  2713.     filesys_initcode = here() + 8 + 0x6c;
  2714.     EXPANSION_bootcode = here () + 8 + 0x14;
  2715.     /* Ouch. Make sure this is _always_ a multiple of two bytes. */
  2716.  db(0x00); db(0x00); db(0x00); db(0x10); db(0x00); db(0x00); db(0x00); db(0x00);
  2717.  db(0x60); db(0x00); db(0x01); db(0xc0); db(0x00); db(0x00); db(0x01); db(0x2c);
  2718.  db(0x00); db(0x00); db(0x00); db(0x6c); db(0x00); db(0x00); db(0x00); db(0x28);
  2719.  db(0x00); db(0x00); db(0x00); db(0x14); db(0x43); db(0xfa); db(0x02); db(0xf9);
  2720.  db(0x4e); db(0xae); db(0xff); db(0xa0); db(0x20); db(0x40); db(0x20); db(0x28);
  2721.  db(0x00); db(0x16); db(0x20); db(0x40); db(0x4e); db(0x90); db(0x4e); db(0x75);
  2722.  db(0x48); db(0xe7); db(0x00); db(0x20); db(0x70); db(0x00); db(0x4e); db(0xb9);
  2723.  db(0x00); db(0xf0); db(0xff); db(0x50); db(0x4a); db(0x80); db(0x67); db(0x2e);
  2724.  db(0x2c); db(0x78); db(0x00); db(0x04); db(0x70); db(0x02); db(0x4e); db(0xb9);
  2725.  db(0x00); db(0xf0); db(0xff); db(0x50); db(0x4a); db(0x80); db(0x67); db(0x14);
  2726.  db(0x24); db(0x40); db(0x70); db(0x03); db(0x4e); db(0xb9); db(0x00); db(0xf0);
  2727.  db(0xff); db(0x50); db(0x20); db(0x4a); db(0x22); db(0x40); db(0x4e); db(0xae);
  2728.  db(0xfe); db(0x92); db(0x60); db(0xe0); db(0x70); db(0x04); db(0x4e); db(0xb9);
  2729.  db(0x00); db(0xf0); db(0xff); db(0x50); db(0x70); db(0x01); db(0x4c); db(0xdf);
  2730.  db(0x04); db(0x00); db(0x4e); db(0x75); db(0x48); db(0xe7); db(0xff); db(0xfe);
  2731.  db(0x2c); db(0x78); db(0x00); db(0x04); db(0x2a); db(0x79); db(0x00); db(0xf0);
  2732.  db(0xff); db(0xfc); db(0x43); db(0xfa); db(0x02); db(0x9f); db(0x70); db(0x24);
  2733.  db(0x7a); db(0x00); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x4a); db(0x80);
  2734.  db(0x66); db(0x0c); db(0x43); db(0xfa); db(0x02); db(0x8f); db(0x70); db(0x00);
  2735.  db(0x7a); db(0x01); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x28); db(0x40);
  2736.  db(0x70); db(0x58); db(0x72); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a);
  2737.  db(0x26); db(0x40); db(0x7e); db(0x54); db(0x27); db(0xb5); db(0x78); db(0x00);
  2738.  db(0x78); db(0x00); db(0x59); db(0x87); db(0x64); db(0xf6); db(0x7c); db(0x00);
  2739.  db(0xbc); db(0xad); db(0x01); db(0x0c); db(0x64); db(0x12); db(0x20); db(0x4b);
  2740.  db(0x48); db(0xe7); db(0x02); db(0x10); db(0x7e); db(0x01); db(0x61); db(0x6c);
  2741.  db(0x4c); db(0xdf); db(0x08); db(0x40); db(0x52); db(0x86); db(0x60); db(0xe8);
  2742.  db(0x2c); db(0x78); db(0x00); db(0x04); db(0x22); db(0x4c); db(0x4e); db(0xae);
  2743.  db(0xfe); db(0x62); db(0x61); db(0x28); db(0x2c); db(0x78); db(0x00); db(0x04);
  2744.  db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x80); db(0x72); db(0x03);
  2745.  db(0x74); db(0xf6); db(0x20); db(0x7c); db(0x00); db(0x20); db(0x00); db(0x00);
  2746.  db(0x90); db(0x88); db(0x65); db(0x0a); db(0x67); db(0x08); db(0x78); db(0x00);
  2747.  db(0x22); db(0x44); db(0x4e); db(0xae); db(0xfd); db(0x96); db(0x4c); db(0xdf);
  2748.  db(0x7f); db(0xff); db(0x4e); db(0x75); db(0x2c); db(0x78); db(0x00); db(0x04);
  2749.  db(0x70); db(0x1a); db(0x22); db(0x3c); db(0x00); db(0x01); db(0x00); db(0x01);
  2750.  db(0x4e); db(0xae); db(0xff); db(0x3a); db(0x22); db(0x40); db(0x41); db(0xfa);
  2751.  db(0x01); db(0xf0); db(0x23); db(0x48); db(0x00); db(0x0a); db(0x41); db(0xfa);
  2752.  db(0xff); db(0x10); db(0x23); db(0x48); db(0x00); db(0x0e); db(0x41); db(0xfa);
  2753.  db(0xff); db(0x08); db(0x23); db(0x48); db(0x00); db(0x12); db(0x70); db(0x0d);
  2754.  db(0x4e); db(0xee); db(0xff); db(0x58); db(0x2a); db(0x79); db(0x00); db(0xf0);
  2755.  db(0xff); db(0xfc); db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x28);
  2756.  db(0x26); db(0x00); db(0xc0); db(0x85); db(0x66); db(0xbc); db(0x2c); db(0x4c);
  2757.  db(0x4e); db(0xae); db(0xff); db(0x70); db(0x26); db(0x40); db(0x4e); db(0xb9);
  2758.  db(0x00); db(0xf0); db(0xff); db(0x20); db(0x70); db(0x00); db(0x27); db(0x40);
  2759.  db(0x00); db(0x08); db(0x27); db(0x40); db(0x00); db(0x10); db(0x27); db(0x40);
  2760.  db(0x00); db(0x20); db(0x4a); db(0x83); db(0x66); db(0x1c); db(0x27); db(0x7c);
  2761.  db(0x00); db(0x00); db(0x0f); db(0xa0); db(0x00); db(0x14); db(0x43); db(0xfa);
  2762.  db(0xfe); db(0x94); db(0x20); db(0x09); db(0xe4); db(0x88); db(0x27); db(0x40);
  2763.  db(0x00); db(0x20); db(0x27); db(0x7c); db(0xff); db(0xff); db(0xff); db(0xff);
  2764.  db(0x00); db(0x24); db(0x4a); db(0x87); db(0x67); db(0x36); db(0x2c); db(0x78);
  2765.  db(0x00); db(0x04); db(0x70); db(0x14); db(0x72); db(0x00); db(0x4e); db(0xae);
  2766.  db(0xff); db(0x3a); db(0x22); db(0x40); db(0x70); db(0x00); db(0x22); db(0x80);
  2767.  db(0x23); db(0x40); db(0x00); db(0x04); db(0x33); db(0x40); db(0x00); db(0x0e);
  2768.  db(0x30); db(0x3c); db(0x10); db(0xff); db(0x90); db(0x06); db(0x33); db(0x40);
  2769.  db(0x00); db(0x08); db(0x23); db(0x6d); db(0x01); db(0x04); db(0x00); db(0x0a);
  2770.  db(0x23); db(0x4b); db(0x00); db(0x10); db(0x41); db(0xec); db(0x00); db(0x4a);
  2771.  db(0x4e); db(0xee); db(0xfe); db(0xf2); db(0x20); db(0x4b); db(0x72); db(0x00);
  2772.  db(0x22); db(0x41); db(0x70); db(0xff); db(0x2c); db(0x4c); db(0x4e); db(0xee);
  2773.  db(0xff); db(0x6a); db(0x2c); db(0x78); db(0x00); db(0x04); db(0x70); db(0x00);
  2774.  db(0x22); db(0x40); db(0x4e); db(0xae); db(0xfe); db(0xda); db(0x20); db(0x40);
  2775.  db(0x4b); db(0xe8); db(0x00); db(0x5c); db(0x43); db(0xfa); db(0x01); db(0x39);
  2776.  db(0x70); db(0x00); db(0x4e); db(0xae); db(0xfd); db(0xd8); db(0x24); db(0x40);
  2777.  db(0x20); db(0x3c); db(0x00); db(0x00); db(0x00); db(0x9d); db(0x22); db(0x3c);
  2778.  db(0x00); db(0x01); db(0x00); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a);
  2779.  db(0x26); db(0x40); db(0x7c); db(0x00); db(0x26); db(0x86); db(0x27); db(0x46);
  2780.  db(0x00); db(0x04); db(0x27); db(0x46); db(0x00); db(0x08); db(0x7a); db(0x00);
  2781.  db(0x20); db(0x4d); db(0x4e); db(0xae); db(0xfe); db(0x80); db(0x20); db(0x4d);
  2782.  db(0x4e); db(0xae); db(0xfe); db(0x8c); db(0x28); db(0x40); db(0x26); db(0x2c);
  2783.  db(0x00); db(0x0a); db(0x70); db(0x00); db(0x4e); db(0xb9); db(0x00); db(0xf0);
  2784.  db(0xff); db(0x40); db(0x60); db(0x74); db(0x20); db(0x4d); db(0x4e); db(0xae);
  2785.  db(0xfe); db(0x80); db(0x20); db(0x4d); db(0x4e); db(0xae); db(0xfe); db(0x8c);
  2786.  db(0x28); db(0x40); db(0x26); db(0x2c); db(0x00); db(0x0a); db(0x66); db(0x38);
  2787.  db(0x70); db(0x01); db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x50);
  2788.  db(0x45); db(0xeb); db(0x00); db(0x04); db(0x20); db(0x52); db(0x20); db(0x08);
  2789.  db(0x67); db(0xda); db(0x22); db(0x50); db(0x20); db(0x40); db(0x20); db(0x28);
  2790.  db(0x00); db(0x04); db(0x6a); db(0x16); db(0x48); db(0xe7); db(0x00); db(0xc0);
  2791.  db(0x28); db(0x68); db(0x00); db(0x0a); db(0x61); db(0x40); db(0x53); db(0x85);
  2792.  db(0x4c); db(0xdf); db(0x03); db(0x00); db(0x24); db(0x89); db(0x20); db(0x49);
  2793.  db(0x60); db(0xdc); db(0x24); db(0x48); db(0x20); db(0x49); db(0x60); db(0xd6);
  2794.  db(0xba); db(0xbc); db(0x00); db(0x00); db(0x00); db(0x14); db(0x65); db(0x08);
  2795.  db(0x70); db(0x01); db(0x29); db(0x40); db(0x00); db(0x04); db(0x60); db(0x0e);
  2796.  db(0x61); db(0x2a); db(0x4e); db(0xb9); db(0x00); db(0xf0); db(0xff); db(0x30);
  2797.  db(0x4a); db(0x80); db(0x67); db(0x0c); db(0x52); db(0x85); db(0x28); db(0xab);
  2798.  db(0x00); db(0x04); db(0x27); db(0x4c); db(0x00); db(0x04); db(0x60); db(0x8c);
  2799.  db(0x28); db(0x43); db(0x61); db(0x02); db(0x60); db(0x86); db(0x22); db(0x54);
  2800.  db(0x20); db(0x6c); db(0x00); db(0x04); db(0x29); db(0x4d); db(0x00); db(0x04);
  2801.  db(0x4e); db(0xee); db(0xfe); db(0x92); db(0x2f); db(0x05); db(0x7a); db(0xfc);
  2802.  db(0x24); db(0x53); db(0x2e); db(0x0a); db(0x22); db(0x0a); db(0x67); db(0x0a);
  2803.  db(0x52); db(0x85); db(0x67); db(0x1e); db(0x22); db(0x4a); db(0x24); db(0x52);
  2804.  db(0x60); db(0xf2); db(0x52); db(0x85); db(0x67); db(0x3c); db(0x24); db(0x47);
  2805.  db(0x70); db(0x18); db(0x72); db(0x01); db(0x4e); db(0xae); db(0xff); db(0x3a);
  2806.  db(0x52); db(0x46); db(0x24); db(0x40); db(0x24); db(0x87); db(0x2e); db(0x0a);
  2807.  db(0x60); db(0xe8); db(0x20); db(0x12); db(0x67); db(0x24); db(0x20); db(0x40);
  2808.  db(0x20); db(0x10); db(0x67); db(0x1e); db(0x20); db(0x40); db(0x20); db(0x10);
  2809.  db(0x67); db(0x18); db(0x70); db(0x00); db(0x22); db(0x80); db(0x22); db(0x4a);
  2810.  db(0x24); db(0x51); db(0x70); db(0x18); db(0x4e); db(0xae); db(0xff); db(0x2e);
  2811.  db(0xdc); db(0xbc); db(0x00); db(0x01); db(0x00); db(0x00); db(0x20); db(0x0a);
  2812.  db(0x66); db(0xec); db(0x26); db(0x87); db(0x2a); db(0x1f); db(0x4e); db(0x75);
  2813.  db(0x55); db(0x41); db(0x45); db(0x20); db(0x66); db(0x69); db(0x6c); db(0x65);
  2814.  db(0x73); db(0x79); db(0x73); db(0x74); db(0x65); db(0x6d); db(0x00); db(0x64);
  2815.  db(0x6f); db(0x73); db(0x2e); db(0x6c); db(0x69); db(0x62); db(0x72); db(0x61);
  2816.  db(0x72); db(0x79); db(0x00); db(0x65); db(0x78); db(0x70); db(0x61); db(0x6e);
  2817.  db(0x73); db(0x69); db(0x6f); db(0x6e); db(0x2e); db(0x6c); db(0x69); db(0x62);
  2818.  db(0x72); db(0x61); db(0x72); db(0x79); db(0x00); db(0x00);
  2819. }
  2820.